17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 521d7f835Sgm149974 * Common Development and Distribution License (the "License"). 621d7f835Sgm149974 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 2153f3aea0SRoger A. Faulkner 227c478bd9Sstevel@tonic-gate /* 238b55d351SSean Wilcox * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. 24*ac0324d2SJerry Jelinek * Copyright (c) 2013, Joyent, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * restarter.c - service manipulation 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * This component manages services whose restarter is svc.startd, the standard 317c478bd9Sstevel@tonic-gate * restarter. It translates restarter protocol events from the graph engine 327c478bd9Sstevel@tonic-gate * into actions on processes, as a delegated restarter would do. 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * The master restarter manages a number of always-running threads: 357c478bd9Sstevel@tonic-gate * - restarter event thread: events from the graph engine 367c478bd9Sstevel@tonic-gate * - timeout thread: thread to fire queued timeouts 377c478bd9Sstevel@tonic-gate * - contract thread: thread to handle contract events 387c478bd9Sstevel@tonic-gate * - wait thread: thread to handle wait-based services 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * The other threads are created as-needed: 417c478bd9Sstevel@tonic-gate * - per-instance method threads 427c478bd9Sstevel@tonic-gate * - per-instance event processing threads 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * The interaction of all threads must result in the following conditions 457c478bd9Sstevel@tonic-gate * being satisfied (on a per-instance basis): 467c478bd9Sstevel@tonic-gate * - restarter events must be processed in order 477c478bd9Sstevel@tonic-gate * - method execution must be serialized 487c478bd9Sstevel@tonic-gate * - instance delete must be held until outstanding methods are complete 497c478bd9Sstevel@tonic-gate * - contract events shouldn't be processed while a method is running 507c478bd9Sstevel@tonic-gate * - timeouts should fire even when a method is running 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * Service instances are represented by restarter_inst_t's and are kept in the 537c478bd9Sstevel@tonic-gate * instance_list list. 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * Service States 567c478bd9Sstevel@tonic-gate * The current state of a service instance is kept in 577c478bd9Sstevel@tonic-gate * restarter_inst_t->ri_i.i_state. If transition to a new state could take 587c478bd9Sstevel@tonic-gate * some time, then before we effect the transition we set 597c478bd9Sstevel@tonic-gate * restarter_inst_t->ri_i.i_next_state to the target state, and afterwards we 607c478bd9Sstevel@tonic-gate * rotate i_next_state to i_state and set i_next_state to 617c478bd9Sstevel@tonic-gate * RESTARTER_STATE_NONE. So usually i_next_state is _NONE when ri_lock is not 627c478bd9Sstevel@tonic-gate * held. The exception is when we launch methods, which are done with 637c478bd9Sstevel@tonic-gate * a separate thread. To keep any other threads from grabbing ri_lock before 647c478bd9Sstevel@tonic-gate * method_thread() does, we set ri_method_thread to the thread id of the 657c478bd9Sstevel@tonic-gate * method thread, and when it is nonzero any thread with a different thread id 667c478bd9Sstevel@tonic-gate * waits on ri_method_cv. 677c478bd9Sstevel@tonic-gate * 687c478bd9Sstevel@tonic-gate * Method execution is serialized by blocking on ri_method_cv in 697c478bd9Sstevel@tonic-gate * inst_lookup_by_id() and waiting for a 0 value of ri_method_thread. This 707c478bd9Sstevel@tonic-gate * also prevents the instance structure from being deleted until all 717c478bd9Sstevel@tonic-gate * outstanding operations such as method_thread() have finished. 727c478bd9Sstevel@tonic-gate * 737c478bd9Sstevel@tonic-gate * Lock ordering: 747c478bd9Sstevel@tonic-gate * 757c478bd9Sstevel@tonic-gate * dgraph_lock [can be held when taking:] 767c478bd9Sstevel@tonic-gate * utmpx_lock 777c478bd9Sstevel@tonic-gate * dictionary->dict_lock 787c478bd9Sstevel@tonic-gate * st->st_load_lock 797c478bd9Sstevel@tonic-gate * wait_info_lock 807c478bd9Sstevel@tonic-gate * ru->restarter_update_lock 817c478bd9Sstevel@tonic-gate * restarter_queue->rpeq_lock 827c478bd9Sstevel@tonic-gate * instance_list.ril_lock 837c478bd9Sstevel@tonic-gate * inst->ri_lock 847c478bd9Sstevel@tonic-gate * st->st_configd_live_lock 857c478bd9Sstevel@tonic-gate * 867c478bd9Sstevel@tonic-gate * instance_list.ril_lock 877c478bd9Sstevel@tonic-gate * graph_queue->gpeq_lock 887c478bd9Sstevel@tonic-gate * gu->gu_lock 897c478bd9Sstevel@tonic-gate * st->st_configd_live_lock 907c478bd9Sstevel@tonic-gate * dictionary->dict_lock 917c478bd9Sstevel@tonic-gate * inst->ri_lock 927c478bd9Sstevel@tonic-gate * graph_queue->gpeq_lock 937c478bd9Sstevel@tonic-gate * gu->gu_lock 947c478bd9Sstevel@tonic-gate * tu->tu_lock 957c478bd9Sstevel@tonic-gate * tq->tq_lock 967c478bd9Sstevel@tonic-gate * inst->ri_queue_lock 977c478bd9Sstevel@tonic-gate * wait_info_lock 987c478bd9Sstevel@tonic-gate * bp->cb_lock 997c478bd9Sstevel@tonic-gate * utmpx_lock 1007c478bd9Sstevel@tonic-gate * 1017c478bd9Sstevel@tonic-gate * single_user_thread_lock 1027c478bd9Sstevel@tonic-gate * wait_info_lock 1037c478bd9Sstevel@tonic-gate * utmpx_lock 1047c478bd9Sstevel@tonic-gate * 1057c478bd9Sstevel@tonic-gate * gu_freeze_lock 1067c478bd9Sstevel@tonic-gate * 1077c478bd9Sstevel@tonic-gate * logbuf_mutex nests inside pretty much everything. 1087c478bd9Sstevel@tonic-gate */ 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate #include <sys/contract/process.h> 1117c478bd9Sstevel@tonic-gate #include <sys/ctfs.h> 1127c478bd9Sstevel@tonic-gate #include <sys/stat.h> 1137c478bd9Sstevel@tonic-gate #include <sys/time.h> 1147c478bd9Sstevel@tonic-gate #include <sys/types.h> 1157c478bd9Sstevel@tonic-gate #include <sys/uio.h> 1167c478bd9Sstevel@tonic-gate #include <sys/wait.h> 1177c478bd9Sstevel@tonic-gate #include <assert.h> 1187c478bd9Sstevel@tonic-gate #include <errno.h> 1197c478bd9Sstevel@tonic-gate #include <fcntl.h> 1207c478bd9Sstevel@tonic-gate #include <libcontract.h> 1217c478bd9Sstevel@tonic-gate #include <libcontract_priv.h> 1227c478bd9Sstevel@tonic-gate #include <libintl.h> 1237c478bd9Sstevel@tonic-gate #include <librestart.h> 1247c478bd9Sstevel@tonic-gate #include <librestart_priv.h> 1257c478bd9Sstevel@tonic-gate #include <libuutil.h> 1267c478bd9Sstevel@tonic-gate #include <limits.h> 1277c478bd9Sstevel@tonic-gate #include <poll.h> 1287c478bd9Sstevel@tonic-gate #include <port.h> 1297c478bd9Sstevel@tonic-gate #include <pthread.h> 1307c478bd9Sstevel@tonic-gate #include <stdarg.h> 1317c478bd9Sstevel@tonic-gate #include <stdio.h> 1327c478bd9Sstevel@tonic-gate #include <strings.h> 1337c478bd9Sstevel@tonic-gate #include <unistd.h> 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate #include "startd.h" 1367c478bd9Sstevel@tonic-gate #include "protocol.h" 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate static uu_list_pool_t *restarter_instance_pool; 1397c478bd9Sstevel@tonic-gate static restarter_instance_list_t instance_list; 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate static uu_list_pool_t *restarter_queue_pool; 1427c478bd9Sstevel@tonic-gate 1432a17138dSJerry Jelinek #define WT_SVC_ERR_THROTTLE 1 /* 1 sec delay for erroring wait svc */ 1442a17138dSJerry Jelinek 14516ba0facSSean Wilcox /* 14616ba0facSSean Wilcox * Function used to reset the restart times for an instance, when 14716ba0facSSean Wilcox * an administrative task comes along and essentially makes the times 14816ba0facSSean Wilcox * in this array ineffective. 14916ba0facSSean Wilcox */ 15016ba0facSSean Wilcox static void 15116ba0facSSean Wilcox reset_start_times(restarter_inst_t *inst) 15216ba0facSSean Wilcox { 15316ba0facSSean Wilcox inst->ri_start_index = 0; 15416ba0facSSean Wilcox bzero(inst->ri_start_time, sizeof (inst->ri_start_time)); 15516ba0facSSean Wilcox } 15616ba0facSSean Wilcox 1577c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1587c478bd9Sstevel@tonic-gate static int 1597c478bd9Sstevel@tonic-gate restarter_instance_compare(const void *lc_arg, const void *rc_arg, 1607c478bd9Sstevel@tonic-gate void *private) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate int lc_id = ((const restarter_inst_t *)lc_arg)->ri_id; 1637c478bd9Sstevel@tonic-gate int rc_id = *(int *)rc_arg; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate if (lc_id > rc_id) 1667c478bd9Sstevel@tonic-gate return (1); 1677c478bd9Sstevel@tonic-gate if (lc_id < rc_id) 1687c478bd9Sstevel@tonic-gate return (-1); 1697c478bd9Sstevel@tonic-gate return (0); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate static restarter_inst_t * 1737c478bd9Sstevel@tonic-gate inst_lookup_by_name(const char *name) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate int id; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate id = dict_lookup_byname(name); 1787c478bd9Sstevel@tonic-gate if (id == -1) 1797c478bd9Sstevel@tonic-gate return (NULL); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate return (inst_lookup_by_id(id)); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate restarter_inst_t * 1857c478bd9Sstevel@tonic-gate inst_lookup_by_id(int id) 1867c478bd9Sstevel@tonic-gate { 1877c478bd9Sstevel@tonic-gate restarter_inst_t *inst; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 1907c478bd9Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 1917c478bd9Sstevel@tonic-gate if (inst != NULL) 1927c478bd9Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 1937c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate if (inst != NULL) { 1967c478bd9Sstevel@tonic-gate while (inst->ri_method_thread != 0 && 1977c478bd9Sstevel@tonic-gate !pthread_equal(inst->ri_method_thread, pthread_self())) { 1987c478bd9Sstevel@tonic-gate ++inst->ri_method_waiters; 1997c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&inst->ri_method_cv, 2007c478bd9Sstevel@tonic-gate &inst->ri_lock); 2017c478bd9Sstevel@tonic-gate assert(inst->ri_method_waiters > 0); 2027c478bd9Sstevel@tonic-gate --inst->ri_method_waiters; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate return (inst); 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate static restarter_inst_t * 2107c478bd9Sstevel@tonic-gate inst_lookup_queue(const char *name) 2117c478bd9Sstevel@tonic-gate { 2127c478bd9Sstevel@tonic-gate int id; 2137c478bd9Sstevel@tonic-gate restarter_inst_t *inst; 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate id = dict_lookup_byname(name); 2167c478bd9Sstevel@tonic-gate if (id == -1) 2177c478bd9Sstevel@tonic-gate return (NULL); 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 2207c478bd9Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 2217c478bd9Sstevel@tonic-gate if (inst != NULL) 2227c478bd9Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_queue_lock); 2237c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate return (inst); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate const char * 2297c478bd9Sstevel@tonic-gate service_style(int flags) 2307c478bd9Sstevel@tonic-gate { 2317c478bd9Sstevel@tonic-gate switch (flags & RINST_STYLE_MASK) { 2327c478bd9Sstevel@tonic-gate case RINST_CONTRACT: return ("contract"); 2337c478bd9Sstevel@tonic-gate case RINST_TRANSIENT: return ("transient"); 2347c478bd9Sstevel@tonic-gate case RINST_WAIT: return ("wait"); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate default: 2377c478bd9Sstevel@tonic-gate #ifndef NDEBUG 2387c478bd9Sstevel@tonic-gate uu_warn("%s:%d: Bad flags 0x%x.\n", __FILE__, __LINE__, flags); 2397c478bd9Sstevel@tonic-gate #endif 2407c478bd9Sstevel@tonic-gate abort(); 2417c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * Fails with ECONNABORTED or ECANCELED. 2477c478bd9Sstevel@tonic-gate */ 2487c478bd9Sstevel@tonic-gate static int 2497c478bd9Sstevel@tonic-gate check_contract(restarter_inst_t *inst, boolean_t primary, 2507c478bd9Sstevel@tonic-gate scf_instance_t *scf_inst) 2517c478bd9Sstevel@tonic-gate { 2527c478bd9Sstevel@tonic-gate ctid_t *ctidp; 2537c478bd9Sstevel@tonic-gate int fd, r; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate ctidp = primary ? &inst->ri_i.i_primary_ctid : 2567c478bd9Sstevel@tonic-gate &inst->ri_i.i_transient_ctid; 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate assert(*ctidp >= 1); 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate fd = contract_open(*ctidp, NULL, "status", O_RDONLY); 2617c478bd9Sstevel@tonic-gate if (fd >= 0) { 2627c478bd9Sstevel@tonic-gate r = close(fd); 2637c478bd9Sstevel@tonic-gate assert(r == 0); 2647c478bd9Sstevel@tonic-gate return (0); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate r = restarter_remove_contract(scf_inst, *ctidp, primary ? 2687c478bd9Sstevel@tonic-gate RESTARTER_CONTRACT_PRIMARY : RESTARTER_CONTRACT_TRANSIENT); 2697c478bd9Sstevel@tonic-gate switch (r) { 2707c478bd9Sstevel@tonic-gate case 0: 2717c478bd9Sstevel@tonic-gate case ECONNABORTED: 2727c478bd9Sstevel@tonic-gate case ECANCELED: 2737c478bd9Sstevel@tonic-gate *ctidp = 0; 2747c478bd9Sstevel@tonic-gate return (r); 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate case ENOMEM: 2777c478bd9Sstevel@tonic-gate uu_die("Out of memory\n"); 2787c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2797c478bd9Sstevel@tonic-gate 2807c478bd9Sstevel@tonic-gate case EPERM: 2817c478bd9Sstevel@tonic-gate uu_die("Insufficient privilege.\n"); 2827c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate case EACCES: 2857c478bd9Sstevel@tonic-gate uu_die("Repository backend access denied.\n"); 2867c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate case EROFS: 2897c478bd9Sstevel@tonic-gate log_error(LOG_INFO, "Could not remove unusable contract id %ld " 2907c478bd9Sstevel@tonic-gate "for %s from repository.\n", *ctidp, inst->ri_i.i_fmri); 2917c478bd9Sstevel@tonic-gate return (0); 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate case EINVAL: 2947c478bd9Sstevel@tonic-gate case EBADF: 2957c478bd9Sstevel@tonic-gate default: 2967c478bd9Sstevel@tonic-gate assert(0); 2977c478bd9Sstevel@tonic-gate abort(); 2987c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate static int stop_instance(scf_handle_t *, restarter_inst_t *, stop_cause_t); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * int restarter_insert_inst(scf_handle_t *, char *) 3067c478bd9Sstevel@tonic-gate * If the inst is already in the restarter list, return its id. If the inst 3077c478bd9Sstevel@tonic-gate * is not in the restarter list, initialize a restarter_inst_t, initialize its 3087c478bd9Sstevel@tonic-gate * states, insert it into the list, and return 0. 3097c478bd9Sstevel@tonic-gate * 3107c478bd9Sstevel@tonic-gate * Fails with 3117c478bd9Sstevel@tonic-gate * ENOENT - name is not in the repository 3127c478bd9Sstevel@tonic-gate */ 3137c478bd9Sstevel@tonic-gate static int 3147c478bd9Sstevel@tonic-gate restarter_insert_inst(scf_handle_t *h, const char *name) 3157c478bd9Sstevel@tonic-gate { 3167c478bd9Sstevel@tonic-gate int id, r; 3177c478bd9Sstevel@tonic-gate restarter_inst_t *inst; 3187c478bd9Sstevel@tonic-gate uu_list_index_t idx; 3197c478bd9Sstevel@tonic-gate scf_service_t *scf_svc; 3207c478bd9Sstevel@tonic-gate scf_instance_t *scf_inst; 32192175b8eSrm88369 scf_snapshot_t *snap = NULL; 3227c478bd9Sstevel@tonic-gate scf_propertygroup_t *pg; 3237c478bd9Sstevel@tonic-gate char *svc_name, *inst_name; 3247c478bd9Sstevel@tonic-gate char logfilebuf[PATH_MAX]; 3257c478bd9Sstevel@tonic-gate char *c; 3267c478bd9Sstevel@tonic-gate boolean_t do_commit_states; 3277c478bd9Sstevel@tonic-gate restarter_instance_state_t state, next_state; 3287c478bd9Sstevel@tonic-gate protocol_states_t *ps; 3297c478bd9Sstevel@tonic-gate pid_t start_pid; 330f6e214c7SGavin Maltby restarter_str_t reason = restarter_str_insert_in_graph; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * We don't use inst_lookup_by_name() here because we want the lookup 3367c478bd9Sstevel@tonic-gate * & insert to be atomic. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate id = dict_lookup_byname(name); 3397c478bd9Sstevel@tonic-gate if (id != -1) { 3407c478bd9Sstevel@tonic-gate inst = uu_list_find(instance_list.ril_instance_list, &id, NULL, 3417c478bd9Sstevel@tonic-gate &idx); 3427c478bd9Sstevel@tonic-gate if (inst != NULL) { 3437c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 3447c478bd9Sstevel@tonic-gate return (0); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* Allocate an instance */ 3497c478bd9Sstevel@tonic-gate inst = startd_zalloc(sizeof (restarter_inst_t)); 3507c478bd9Sstevel@tonic-gate inst->ri_utmpx_prefix = startd_alloc(max_scf_value_size); 3517c478bd9Sstevel@tonic-gate inst->ri_utmpx_prefix[0] = '\0'; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri = startd_alloc(strlen(name) + 1); 3547c478bd9Sstevel@tonic-gate (void) strcpy((char *)inst->ri_i.i_fmri, name); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate inst->ri_queue = startd_list_create(restarter_queue_pool, inst, 0); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * id shouldn't be -1 since we use the same dictionary as graph.c, but 3607c478bd9Sstevel@tonic-gate * just in case. 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate inst->ri_id = (id != -1 ? id : dict_insert(name)); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate special_online_hooks_get(name, &inst->ri_pre_online_hook, 3657c478bd9Sstevel@tonic-gate &inst->ri_post_online_hook, &inst->ri_post_offline_hook); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate scf_svc = safe_scf_service_create(h); 3687c478bd9Sstevel@tonic-gate scf_inst = safe_scf_instance_create(h); 3697c478bd9Sstevel@tonic-gate pg = safe_scf_pg_create(h); 3707c478bd9Sstevel@tonic-gate svc_name = startd_alloc(max_scf_name_size); 3717c478bd9Sstevel@tonic-gate inst_name = startd_alloc(max_scf_name_size); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate rep_retry: 37492175b8eSrm88369 if (snap != NULL) 37592175b8eSrm88369 scf_snapshot_destroy(snap); 37692175b8eSrm88369 if (inst->ri_logstem != NULL) 37792175b8eSrm88369 startd_free(inst->ri_logstem, PATH_MAX); 37892175b8eSrm88369 if (inst->ri_common_name != NULL) 379c8faf4ecSJerry Jelinek free(inst->ri_common_name); 38092175b8eSrm88369 if (inst->ri_C_common_name != NULL) 381c8faf4ecSJerry Jelinek free(inst->ri_C_common_name); 38292175b8eSrm88369 snap = NULL; 38392175b8eSrm88369 inst->ri_logstem = NULL; 38492175b8eSrm88369 inst->ri_common_name = NULL; 38592175b8eSrm88369 inst->ri_C_common_name = NULL; 38692175b8eSrm88369 3877c478bd9Sstevel@tonic-gate if (scf_handle_decode_fmri(h, name, NULL, scf_svc, scf_inst, NULL, 3887c478bd9Sstevel@tonic-gate NULL, SCF_DECODE_FMRI_EXACT) != 0) { 3897c478bd9Sstevel@tonic-gate switch (scf_error()) { 3907c478bd9Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 3917c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 3927c478bd9Sstevel@tonic-gate goto rep_retry; 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 39592175b8eSrm88369 goto deleted; 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate uu_die("Can't decode FMRI %s: %s\n", name, 3997c478bd9Sstevel@tonic-gate scf_strerror(scf_error())); 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /* 4037c478bd9Sstevel@tonic-gate * If there's no running snapshot, then we execute using the editing 4047c478bd9Sstevel@tonic-gate * snapshot. Pending snapshots will be taken later. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate snap = libscf_get_running_snapshot(scf_inst); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate if ((scf_service_get_name(scf_svc, svc_name, max_scf_name_size) < 0) || 4097c478bd9Sstevel@tonic-gate (scf_instance_get_name(scf_inst, inst_name, max_scf_name_size) < 4107c478bd9Sstevel@tonic-gate 0)) { 4117c478bd9Sstevel@tonic-gate switch (scf_error()) { 4127c478bd9Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 4137c478bd9Sstevel@tonic-gate break; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 4167c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 4177c478bd9Sstevel@tonic-gate goto rep_retry; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate default: 4207c478bd9Sstevel@tonic-gate assert(0); 4217c478bd9Sstevel@tonic-gate abort(); 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate goto deleted; 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4271855af6bSlianep (void) snprintf(logfilebuf, PATH_MAX, "%s:%s", svc_name, inst_name); 4281855af6bSlianep for (c = logfilebuf; *c != '\0'; c++) 4291855af6bSlianep if (*c == '/') 4301855af6bSlianep *c = '-'; 4311855af6bSlianep 4321855af6bSlianep inst->ri_logstem = startd_alloc(PATH_MAX); 4331855af6bSlianep (void) snprintf(inst->ri_logstem, PATH_MAX, "%s%s", logfilebuf, 4341855af6bSlianep LOG_SUFFIX); 4351855af6bSlianep 4367c478bd9Sstevel@tonic-gate /* 4377c478bd9Sstevel@tonic-gate * If the restarter group is missing, use uninit/none. Otherwise, 4387c478bd9Sstevel@tonic-gate * we're probably being restarted & don't want to mess up the states 4397c478bd9Sstevel@tonic-gate * that are there. 4407c478bd9Sstevel@tonic-gate */ 4417c478bd9Sstevel@tonic-gate state = RESTARTER_STATE_UNINIT; 4427c478bd9Sstevel@tonic-gate next_state = RESTARTER_STATE_NONE; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate r = scf_instance_get_pg(scf_inst, SCF_PG_RESTARTER, pg); 4457c478bd9Sstevel@tonic-gate if (r != 0) { 4467c478bd9Sstevel@tonic-gate switch (scf_error()) { 4477c478bd9Sstevel@tonic-gate case SCF_ERROR_CONNECTION_BROKEN: 4487c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 4497c478bd9Sstevel@tonic-gate goto rep_retry; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate case SCF_ERROR_NOT_SET: 4527c478bd9Sstevel@tonic-gate goto deleted; 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate case SCF_ERROR_NOT_FOUND: 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * This shouldn't happen since the graph engine should 4577c478bd9Sstevel@tonic-gate * have initialized the state to uninitialized/none if 4587c478bd9Sstevel@tonic-gate * there was no restarter pg. In case somebody 4597c478bd9Sstevel@tonic-gate * deleted it, though.... 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate do_commit_states = B_TRUE; 4627c478bd9Sstevel@tonic-gate break; 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate default: 4657c478bd9Sstevel@tonic-gate assert(0); 4667c478bd9Sstevel@tonic-gate abort(); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate } else { 4697c478bd9Sstevel@tonic-gate r = libscf_read_states(pg, &state, &next_state); 4707c478bd9Sstevel@tonic-gate if (r != 0) { 4717c478bd9Sstevel@tonic-gate do_commit_states = B_TRUE; 4727c478bd9Sstevel@tonic-gate } else { 4737c478bd9Sstevel@tonic-gate if (next_state != RESTARTER_STATE_NONE) { 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate * Force next_state to _NONE since we 4767c478bd9Sstevel@tonic-gate * don't look for method processes. 4777c478bd9Sstevel@tonic-gate */ 4787c478bd9Sstevel@tonic-gate next_state = RESTARTER_STATE_NONE; 4797c478bd9Sstevel@tonic-gate do_commit_states = B_TRUE; 4807c478bd9Sstevel@tonic-gate } else { 4817c478bd9Sstevel@tonic-gate /* 482f6e214c7SGavin Maltby * The reason for transition will depend on 483f6e214c7SGavin Maltby * state. 484f6e214c7SGavin Maltby */ 485f6e214c7SGavin Maltby if (st->st_initial == 0) 486f6e214c7SGavin Maltby reason = restarter_str_startd_restart; 487f6e214c7SGavin Maltby else if (state == RESTARTER_STATE_MAINT) 488f6e214c7SGavin Maltby reason = restarter_str_bad_repo_state; 489f6e214c7SGavin Maltby /* 4907c478bd9Sstevel@tonic-gate * Inform the restarter of our state without 4917c478bd9Sstevel@tonic-gate * changing the STIME in the repository. 4927c478bd9Sstevel@tonic-gate */ 4937c478bd9Sstevel@tonic-gate ps = startd_alloc(sizeof (*ps)); 4947c478bd9Sstevel@tonic-gate inst->ri_i.i_state = ps->ps_state = state; 4957c478bd9Sstevel@tonic-gate inst->ri_i.i_next_state = ps->ps_state_next = 4967c478bd9Sstevel@tonic-gate next_state; 497f6e214c7SGavin Maltby ps->ps_reason = reason; 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate graph_protocol_send_event(inst->ri_i.i_fmri, 5007c478bd9Sstevel@tonic-gate GRAPH_UPDATE_STATE_CHANGE, ps); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate do_commit_states = B_FALSE; 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate switch (libscf_get_startd_properties(scf_inst, snap, &inst->ri_flags, 5087c478bd9Sstevel@tonic-gate &inst->ri_utmpx_prefix)) { 5097c478bd9Sstevel@tonic-gate case 0: 5107c478bd9Sstevel@tonic-gate break; 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate case ECONNABORTED: 5137c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 5147c478bd9Sstevel@tonic-gate goto rep_retry; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate case ECANCELED: 5177c478bd9Sstevel@tonic-gate goto deleted; 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate case ENOENT: 5207c478bd9Sstevel@tonic-gate /* 5217c478bd9Sstevel@tonic-gate * This is odd, because the graph engine should have required 5227c478bd9Sstevel@tonic-gate * the general property group. So we'll just use default 5237c478bd9Sstevel@tonic-gate * flags in anticipation of the graph engine sending us 5247c478bd9Sstevel@tonic-gate * REMOVE_INSTANCE when it finds out that the general property 5257c478bd9Sstevel@tonic-gate * group has been deleted. 5267c478bd9Sstevel@tonic-gate */ 5277c478bd9Sstevel@tonic-gate inst->ri_flags = RINST_CONTRACT; 5287c478bd9Sstevel@tonic-gate break; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate default: 5317c478bd9Sstevel@tonic-gate assert(0); 5327c478bd9Sstevel@tonic-gate abort(); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate 5353dd94f79SBryan Cantrill r = libscf_get_template_values(scf_inst, snap, 5363dd94f79SBryan Cantrill &inst->ri_common_name, &inst->ri_C_common_name); 5373dd94f79SBryan Cantrill 5383dd94f79SBryan Cantrill /* 5393dd94f79SBryan Cantrill * Copy our names to smaller buffers to reduce our memory footprint. 5403dd94f79SBryan Cantrill */ 5413dd94f79SBryan Cantrill if (inst->ri_common_name != NULL) { 5423dd94f79SBryan Cantrill char *tmp = safe_strdup(inst->ri_common_name); 5433dd94f79SBryan Cantrill startd_free(inst->ri_common_name, max_scf_value_size); 5443dd94f79SBryan Cantrill inst->ri_common_name = tmp; 5453dd94f79SBryan Cantrill } 5463dd94f79SBryan Cantrill 5473dd94f79SBryan Cantrill if (inst->ri_C_common_name != NULL) { 5483dd94f79SBryan Cantrill char *tmp = safe_strdup(inst->ri_C_common_name); 5493dd94f79SBryan Cantrill startd_free(inst->ri_C_common_name, max_scf_value_size); 5503dd94f79SBryan Cantrill inst->ri_C_common_name = tmp; 5513dd94f79SBryan Cantrill } 5523dd94f79SBryan Cantrill 5533dd94f79SBryan Cantrill switch (r) { 5547c478bd9Sstevel@tonic-gate case 0: 5557c478bd9Sstevel@tonic-gate break; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate case ECONNABORTED: 5587c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 5597c478bd9Sstevel@tonic-gate goto rep_retry; 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate case ECANCELED: 5627c478bd9Sstevel@tonic-gate goto deleted; 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate case ECHILD: 5657c478bd9Sstevel@tonic-gate case ENOENT: 5667c478bd9Sstevel@tonic-gate break; 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate default: 5697c478bd9Sstevel@tonic-gate assert(0); 5707c478bd9Sstevel@tonic-gate abort(); 5717c478bd9Sstevel@tonic-gate } 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate switch (libscf_read_method_ids(h, scf_inst, inst->ri_i.i_fmri, 5747c478bd9Sstevel@tonic-gate &inst->ri_i.i_primary_ctid, &inst->ri_i.i_transient_ctid, 5757c478bd9Sstevel@tonic-gate &start_pid)) { 5767c478bd9Sstevel@tonic-gate case 0: 5777c478bd9Sstevel@tonic-gate break; 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate case ECONNABORTED: 5807c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 5817c478bd9Sstevel@tonic-gate goto rep_retry; 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate case ECANCELED: 5847c478bd9Sstevel@tonic-gate goto deleted; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate default: 5877c478bd9Sstevel@tonic-gate assert(0); 5887c478bd9Sstevel@tonic-gate abort(); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid >= 1) { 5927c478bd9Sstevel@tonic-gate contract_hash_store(inst->ri_i.i_primary_ctid, inst->ri_id); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate switch (check_contract(inst, B_TRUE, scf_inst)) { 5957c478bd9Sstevel@tonic-gate case 0: 5967c478bd9Sstevel@tonic-gate break; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate case ECONNABORTED: 5997c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 6007c478bd9Sstevel@tonic-gate goto rep_retry; 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate case ECANCELED: 6037c478bd9Sstevel@tonic-gate goto deleted; 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate default: 6067c478bd9Sstevel@tonic-gate assert(0); 6077c478bd9Sstevel@tonic-gate abort(); 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (inst->ri_i.i_transient_ctid >= 1) { 6127c478bd9Sstevel@tonic-gate switch (check_contract(inst, B_FALSE, scf_inst)) { 6137c478bd9Sstevel@tonic-gate case 0: 6147c478bd9Sstevel@tonic-gate break; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate case ECONNABORTED: 6177c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 6187c478bd9Sstevel@tonic-gate goto rep_retry; 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate case ECANCELED: 6217c478bd9Sstevel@tonic-gate goto deleted; 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate default: 6247c478bd9Sstevel@tonic-gate assert(0); 6257c478bd9Sstevel@tonic-gate abort(); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* No more failures we live through, so add it to the list. */ 6307c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&inst->ri_lock, &mutex_attrs); 6317c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&inst->ri_queue_lock, &mutex_attrs); 6327c478bd9Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 6337c478bd9Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_queue_lock); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&inst->ri_method_cv, NULL); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate uu_list_node_init(inst, &inst->ri_link, restarter_instance_pool); 6387c478bd9Sstevel@tonic-gate uu_list_insert(instance_list.ril_instance_list, inst, idx); 6397c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate if (start_pid != -1 && 6427c478bd9Sstevel@tonic-gate (inst->ri_flags & RINST_STYLE_MASK) == RINST_WAIT) { 6437c478bd9Sstevel@tonic-gate int ret; 6447c478bd9Sstevel@tonic-gate ret = wait_register(start_pid, inst->ri_i.i_fmri, 0, 1); 6457c478bd9Sstevel@tonic-gate if (ret == -1) { 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate * Implication: if we can't reregister the 6487c478bd9Sstevel@tonic-gate * instance, we will start another one. Two 6497c478bd9Sstevel@tonic-gate * instances may or may not result in a resource 6507c478bd9Sstevel@tonic-gate * conflict. 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate log_error(LOG_WARNING, 6537c478bd9Sstevel@tonic-gate "%s: couldn't reregister %ld for wait\n", 6547c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri, start_pid); 6557c478bd9Sstevel@tonic-gate } else if (ret == 1) { 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * Leading PID has exited. 6587c478bd9Sstevel@tonic-gate */ 6597c478bd9Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_EXIT); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate scf_pg_destroy(pg); 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate if (do_commit_states) 6677c478bd9Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, state, 668f6e214c7SGavin Maltby next_state, RERR_NONE, reason); 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s is a %s-style service\n", name, 6717c478bd9Sstevel@tonic-gate service_style(inst->ri_flags)); 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_queue_lock); 6747c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate startd_free(svc_name, max_scf_name_size); 6777c478bd9Sstevel@tonic-gate startd_free(inst_name, max_scf_name_size); 6787c478bd9Sstevel@tonic-gate scf_snapshot_destroy(snap); 6797c478bd9Sstevel@tonic-gate scf_instance_destroy(scf_inst); 6807c478bd9Sstevel@tonic-gate scf_service_destroy(scf_svc); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: inserted instance into restarter list\n", 6837c478bd9Sstevel@tonic-gate name); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate return (0); 68692175b8eSrm88369 68792175b8eSrm88369 deleted: 68892175b8eSrm88369 MUTEX_UNLOCK(&instance_list.ril_lock); 68992175b8eSrm88369 startd_free(inst_name, max_scf_name_size); 69092175b8eSrm88369 startd_free(svc_name, max_scf_name_size); 69192175b8eSrm88369 if (snap != NULL) 69292175b8eSrm88369 scf_snapshot_destroy(snap); 69392175b8eSrm88369 scf_pg_destroy(pg); 69492175b8eSrm88369 scf_instance_destroy(scf_inst); 69592175b8eSrm88369 scf_service_destroy(scf_svc); 69692175b8eSrm88369 startd_free((void *)inst->ri_i.i_fmri, strlen(inst->ri_i.i_fmri) + 1); 69792175b8eSrm88369 uu_list_destroy(inst->ri_queue); 69892175b8eSrm88369 if (inst->ri_logstem != NULL) 69992175b8eSrm88369 startd_free(inst->ri_logstem, PATH_MAX); 70092175b8eSrm88369 if (inst->ri_common_name != NULL) 701c8faf4ecSJerry Jelinek free(inst->ri_common_name); 70292175b8eSrm88369 if (inst->ri_C_common_name != NULL) 703c8faf4ecSJerry Jelinek free(inst->ri_C_common_name); 70492175b8eSrm88369 startd_free(inst->ri_utmpx_prefix, max_scf_value_size); 70592175b8eSrm88369 startd_free(inst, sizeof (restarter_inst_t)); 70692175b8eSrm88369 return (ENOENT); 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate static void 7107c478bd9Sstevel@tonic-gate restarter_delete_inst(restarter_inst_t *ri) 7117c478bd9Sstevel@tonic-gate { 7127c478bd9Sstevel@tonic-gate int id; 7137c478bd9Sstevel@tonic-gate restarter_inst_t *rip; 7147c478bd9Sstevel@tonic-gate void *cookie = NULL; 7157c478bd9Sstevel@tonic-gate restarter_instance_qentry_t *e; 7167c478bd9Sstevel@tonic-gate 71753f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&ri->ri_lock)); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * Must drop the instance lock so we can pick up the instance_list 7217c478bd9Sstevel@tonic-gate * lock & remove the instance. 7227c478bd9Sstevel@tonic-gate */ 7237c478bd9Sstevel@tonic-gate id = ri->ri_id; 7247c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&ri->ri_lock); 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate rip = uu_list_find(instance_list.ril_instance_list, &id, NULL, NULL); 7297c478bd9Sstevel@tonic-gate if (rip == NULL) { 7307c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 7317c478bd9Sstevel@tonic-gate return; 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate assert(ri == rip); 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate uu_list_remove(instance_list.ril_instance_list, ri); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: deleted instance from restarter list\n", 7397c478bd9Sstevel@tonic-gate ri->ri_i.i_fmri); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * We can lock the instance without holding the instance_list lock 7457c478bd9Sstevel@tonic-gate * since we removed the instance from the list. 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate MUTEX_LOCK(&ri->ri_lock); 7487c478bd9Sstevel@tonic-gate MUTEX_LOCK(&ri->ri_queue_lock); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate if (ri->ri_i.i_primary_ctid >= 1) 7517c478bd9Sstevel@tonic-gate contract_hash_remove(ri->ri_i.i_primary_ctid); 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate while (ri->ri_method_thread != 0 || ri->ri_method_waiters > 0) 7547c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&ri->ri_method_cv, &ri->ri_lock); 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate while ((e = uu_list_teardown(ri->ri_queue, &cookie)) != NULL) 7577c478bd9Sstevel@tonic-gate startd_free(e, sizeof (*e)); 7587c478bd9Sstevel@tonic-gate uu_list_destroy(ri->ri_queue); 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate startd_free((void *)ri->ri_i.i_fmri, strlen(ri->ri_i.i_fmri) + 1); 7611855af6bSlianep startd_free(ri->ri_logstem, PATH_MAX); 7623ba60fe0Srm88369 if (ri->ri_common_name != NULL) 763c8faf4ecSJerry Jelinek free(ri->ri_common_name); 7643ba60fe0Srm88369 if (ri->ri_C_common_name != NULL) 765c8faf4ecSJerry Jelinek free(ri->ri_C_common_name); 7667c478bd9Sstevel@tonic-gate startd_free(ri->ri_utmpx_prefix, max_scf_value_size); 7677c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&ri->ri_lock); 7687c478bd9Sstevel@tonic-gate (void) pthread_mutex_destroy(&ri->ri_queue_lock); 7697c478bd9Sstevel@tonic-gate startd_free(ri, sizeof (restarter_inst_t)); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * instance_is_wait_style() 7747c478bd9Sstevel@tonic-gate * 7757c478bd9Sstevel@tonic-gate * Returns 1 if the given instance is a "wait-style" service instance. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate int 7787c478bd9Sstevel@tonic-gate instance_is_wait_style(restarter_inst_t *inst) 7797c478bd9Sstevel@tonic-gate { 78053f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 7817c478bd9Sstevel@tonic-gate return ((inst->ri_flags & RINST_STYLE_MASK) == RINST_WAIT); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate /* 7857c478bd9Sstevel@tonic-gate * instance_is_transient_style() 7867c478bd9Sstevel@tonic-gate * 7877c478bd9Sstevel@tonic-gate * Returns 1 if the given instance is a transient service instance. 7887c478bd9Sstevel@tonic-gate */ 7897c478bd9Sstevel@tonic-gate int 7907c478bd9Sstevel@tonic-gate instance_is_transient_style(restarter_inst_t *inst) 7917c478bd9Sstevel@tonic-gate { 79253f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 7937c478bd9Sstevel@tonic-gate return ((inst->ri_flags & RINST_STYLE_MASK) == RINST_TRANSIENT); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate /* 7977c478bd9Sstevel@tonic-gate * instance_in_transition() 7987c478bd9Sstevel@tonic-gate * Returns 1 if instance is in transition, 0 if not 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate int 8017c478bd9Sstevel@tonic-gate instance_in_transition(restarter_inst_t *inst) 8027c478bd9Sstevel@tonic-gate { 80353f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 8047c478bd9Sstevel@tonic-gate if (inst->ri_i.i_next_state == RESTARTER_STATE_NONE) 8057c478bd9Sstevel@tonic-gate return (0); 8067c478bd9Sstevel@tonic-gate return (1); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* 81021d7f835Sgm149974 * returns 1 if instance is already started, 0 if not 81121d7f835Sgm149974 */ 81221d7f835Sgm149974 static int 81321d7f835Sgm149974 instance_started(restarter_inst_t *inst) 81421d7f835Sgm149974 { 81521d7f835Sgm149974 int ret; 81621d7f835Sgm149974 81753f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 81821d7f835Sgm149974 81921d7f835Sgm149974 if (inst->ri_i.i_state == RESTARTER_STATE_ONLINE || 82021d7f835Sgm149974 inst->ri_i.i_state == RESTARTER_STATE_DEGRADED) 82121d7f835Sgm149974 ret = 1; 82221d7f835Sgm149974 else 82321d7f835Sgm149974 ret = 0; 82421d7f835Sgm149974 82521d7f835Sgm149974 return (ret); 82621d7f835Sgm149974 } 82721d7f835Sgm149974 82821d7f835Sgm149974 /* 8297c478bd9Sstevel@tonic-gate * Returns 8307c478bd9Sstevel@tonic-gate * 0 - success 8317c478bd9Sstevel@tonic-gate * ECONNRESET - success, but h was rebound 8327c478bd9Sstevel@tonic-gate */ 8337c478bd9Sstevel@tonic-gate int 8347c478bd9Sstevel@tonic-gate restarter_instance_update_states(scf_handle_t *h, restarter_inst_t *ri, 8357c478bd9Sstevel@tonic-gate restarter_instance_state_t new_state, 836f6e214c7SGavin Maltby restarter_instance_state_t new_state_next, restarter_error_t err, 837f6e214c7SGavin Maltby restarter_str_t reason) 8387c478bd9Sstevel@tonic-gate { 8397c478bd9Sstevel@tonic-gate protocol_states_t *states; 8407c478bd9Sstevel@tonic-gate int e; 8417c478bd9Sstevel@tonic-gate uint_t retry_count = 0, msecs = ALLOC_DELAY; 8427c478bd9Sstevel@tonic-gate boolean_t rebound = B_FALSE; 84321d7f835Sgm149974 int prev_state_online; 84421d7f835Sgm149974 int state_online; 8457c478bd9Sstevel@tonic-gate 84653f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&ri->ri_lock)); 8477c478bd9Sstevel@tonic-gate 84821d7f835Sgm149974 prev_state_online = instance_started(ri); 84921d7f835Sgm149974 8507c478bd9Sstevel@tonic-gate retry: 8517c478bd9Sstevel@tonic-gate e = _restarter_commit_states(h, &ri->ri_i, new_state, new_state_next, 852f6e214c7SGavin Maltby restarter_get_str_short(reason)); 8537c478bd9Sstevel@tonic-gate switch (e) { 8547c478bd9Sstevel@tonic-gate case 0: 8557c478bd9Sstevel@tonic-gate break; 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate case ENOMEM: 8587c478bd9Sstevel@tonic-gate ++retry_count; 8597c478bd9Sstevel@tonic-gate if (retry_count < ALLOC_RETRY) { 8607c478bd9Sstevel@tonic-gate (void) poll(NULL, 0, msecs); 8617c478bd9Sstevel@tonic-gate msecs *= ALLOC_DELAY_MULT; 8627c478bd9Sstevel@tonic-gate goto retry; 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* Like startd_alloc(). */ 8667c478bd9Sstevel@tonic-gate uu_die("Insufficient memory.\n"); 8677c478bd9Sstevel@tonic-gate /* NOTREACHED */ 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate case ECONNABORTED: 8707c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 8717c478bd9Sstevel@tonic-gate rebound = B_TRUE; 8727c478bd9Sstevel@tonic-gate goto retry; 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate case EPERM: 8757c478bd9Sstevel@tonic-gate case EACCES: 8767c478bd9Sstevel@tonic-gate case EROFS: 8777c478bd9Sstevel@tonic-gate log_error(LOG_NOTICE, "Could not commit state change for %s " 8787c478bd9Sstevel@tonic-gate "to repository: %s.\n", ri->ri_i.i_fmri, strerror(e)); 8797c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 8807c478bd9Sstevel@tonic-gate 8817c478bd9Sstevel@tonic-gate case ENOENT: 8827c478bd9Sstevel@tonic-gate ri->ri_i.i_state = new_state; 8837c478bd9Sstevel@tonic-gate ri->ri_i.i_next_state = new_state_next; 8847c478bd9Sstevel@tonic-gate break; 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate case EINVAL: 8877c478bd9Sstevel@tonic-gate default: 8887c478bd9Sstevel@tonic-gate bad_error("_restarter_commit_states", e); 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate states = startd_alloc(sizeof (protocol_states_t)); 8927c478bd9Sstevel@tonic-gate states->ps_state = new_state; 8937c478bd9Sstevel@tonic-gate states->ps_state_next = new_state_next; 8947c478bd9Sstevel@tonic-gate states->ps_err = err; 895f6e214c7SGavin Maltby states->ps_reason = reason; 8967c478bd9Sstevel@tonic-gate graph_protocol_send_event(ri->ri_i.i_fmri, GRAPH_UPDATE_STATE_CHANGE, 8977c478bd9Sstevel@tonic-gate (void *)states); 8987c478bd9Sstevel@tonic-gate 89921d7f835Sgm149974 state_online = instance_started(ri); 90021d7f835Sgm149974 90121d7f835Sgm149974 if (prev_state_online && !state_online) 90221d7f835Sgm149974 ri->ri_post_offline_hook(); 90321d7f835Sgm149974 else if (!prev_state_online && state_online) 9047c478bd9Sstevel@tonic-gate ri->ri_post_online_hook(); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate return (rebound ? ECONNRESET : 0); 9077c478bd9Sstevel@tonic-gate } 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate void 9107c478bd9Sstevel@tonic-gate restarter_mark_pending_snapshot(const char *fmri, uint_t flag) 9117c478bd9Sstevel@tonic-gate { 9127c478bd9Sstevel@tonic-gate restarter_inst_t *inst; 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate assert(flag == RINST_RETAKE_RUNNING || flag == RINST_RETAKE_START); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate inst = inst_lookup_by_name(fmri); 9177c478bd9Sstevel@tonic-gate if (inst == NULL) 9187c478bd9Sstevel@tonic-gate return; 9197c478bd9Sstevel@tonic-gate 9207c478bd9Sstevel@tonic-gate inst->ri_flags |= flag; 9217c478bd9Sstevel@tonic-gate 9227c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate static void 9267c478bd9Sstevel@tonic-gate restarter_take_pending_snapshots(scf_handle_t *h) 9277c478bd9Sstevel@tonic-gate { 9287c478bd9Sstevel@tonic-gate restarter_inst_t *inst; 9297c478bd9Sstevel@tonic-gate int r; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate MUTEX_LOCK(&instance_list.ril_lock); 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate for (inst = uu_list_first(instance_list.ril_instance_list); 9347c478bd9Sstevel@tonic-gate inst != NULL; 9357c478bd9Sstevel@tonic-gate inst = uu_list_next(instance_list.ril_instance_list, inst)) { 9367c478bd9Sstevel@tonic-gate const char *fmri; 9377c478bd9Sstevel@tonic-gate scf_instance_t *sinst = NULL; 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate MUTEX_LOCK(&inst->ri_lock); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate /* 9427c478bd9Sstevel@tonic-gate * This is where we'd check inst->ri_method_thread and if it 9437c478bd9Sstevel@tonic-gate * were nonzero we'd wait in anticipation of another thread 9447c478bd9Sstevel@tonic-gate * executing a method for inst. Doing so with the instance_list 9457c478bd9Sstevel@tonic-gate * locked, though, leads to deadlock. Since taking a snapshot 9467c478bd9Sstevel@tonic-gate * during that window won't hurt anything, we'll just continue. 9477c478bd9Sstevel@tonic-gate */ 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate fmri = inst->ri_i.i_fmri; 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate if (inst->ri_flags & RINST_RETAKE_RUNNING) { 9527c478bd9Sstevel@tonic-gate scf_snapshot_t *rsnap; 9537c478bd9Sstevel@tonic-gate 9547c478bd9Sstevel@tonic-gate (void) libscf_fmri_get_instance(h, fmri, &sinst); 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate rsnap = libscf_get_or_make_running_snapshot(sinst, 9577c478bd9Sstevel@tonic-gate fmri, B_FALSE); 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate scf_instance_destroy(sinst); 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (rsnap != NULL) 9627c478bd9Sstevel@tonic-gate inst->ri_flags &= ~RINST_RETAKE_RUNNING; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate scf_snapshot_destroy(rsnap); 9657c478bd9Sstevel@tonic-gate } 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate if (inst->ri_flags & RINST_RETAKE_START) { 9687c478bd9Sstevel@tonic-gate switch (r = libscf_snapshots_poststart(h, fmri, 9697c478bd9Sstevel@tonic-gate B_FALSE)) { 9707c478bd9Sstevel@tonic-gate case 0: 9717c478bd9Sstevel@tonic-gate case ENOENT: 9727c478bd9Sstevel@tonic-gate inst->ri_flags &= ~RINST_RETAKE_START; 9737c478bd9Sstevel@tonic-gate break; 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate case ECONNABORTED: 9767c478bd9Sstevel@tonic-gate break; 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate case EACCES: 9797c478bd9Sstevel@tonic-gate default: 9807c478bd9Sstevel@tonic-gate bad_error("libscf_snapshots_poststart", r); 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 9857c478bd9Sstevel@tonic-gate } 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&instance_list.ril_lock); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9917c478bd9Sstevel@tonic-gate void * 9927c478bd9Sstevel@tonic-gate restarter_post_fsminimal_thread(void *unused) 9937c478bd9Sstevel@tonic-gate { 9947c478bd9Sstevel@tonic-gate scf_handle_t *h; 9957c478bd9Sstevel@tonic-gate int r; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate for (;;) { 10007c478bd9Sstevel@tonic-gate r = libscf_create_self(h); 10017c478bd9Sstevel@tonic-gate if (r == 0) 10027c478bd9Sstevel@tonic-gate break; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate assert(r == ECONNABORTED); 10057c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate restarter_take_pending_snapshots(h); 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate (void) scf_handle_unbind(h); 10117c478bd9Sstevel@tonic-gate scf_handle_destroy(h); 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate return (NULL); 10147c478bd9Sstevel@tonic-gate } 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* 10177c478bd9Sstevel@tonic-gate * int stop_instance() 10187c478bd9Sstevel@tonic-gate * 10197c478bd9Sstevel@tonic-gate * Stop the instance identified by the instance given as the second argument, 10207c478bd9Sstevel@tonic-gate * for the cause stated. 10217c478bd9Sstevel@tonic-gate * 10227c478bd9Sstevel@tonic-gate * Returns 10237c478bd9Sstevel@tonic-gate * 0 - success 10247c478bd9Sstevel@tonic-gate * -1 - inst is in transition 10257c478bd9Sstevel@tonic-gate */ 10267c478bd9Sstevel@tonic-gate static int 10277c478bd9Sstevel@tonic-gate stop_instance(scf_handle_t *local_handle, restarter_inst_t *inst, 10287c478bd9Sstevel@tonic-gate stop_cause_t cause) 10297c478bd9Sstevel@tonic-gate { 10307c478bd9Sstevel@tonic-gate fork_info_t *info; 10317c478bd9Sstevel@tonic-gate const char *cp; 10327c478bd9Sstevel@tonic-gate int err; 10337c478bd9Sstevel@tonic-gate restarter_error_t re; 1034f6e214c7SGavin Maltby restarter_str_t reason; 10352a17138dSJerry Jelinek restarter_instance_state_t new_state; 10367c478bd9Sstevel@tonic-gate 103753f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 10387c478bd9Sstevel@tonic-gate assert(inst->ri_method_thread == 0); 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate switch (cause) { 10417c478bd9Sstevel@tonic-gate case RSTOP_EXIT: 10427c478bd9Sstevel@tonic-gate re = RERR_RESTART; 1043f6e214c7SGavin Maltby reason = restarter_str_ct_ev_exit; 10447c478bd9Sstevel@tonic-gate cp = "all processes in service exited"; 10457c478bd9Sstevel@tonic-gate break; 10462a17138dSJerry Jelinek case RSTOP_ERR_CFG: 10472a17138dSJerry Jelinek re = RERR_FAULT; 10482a17138dSJerry Jelinek reason = restarter_str_method_failed; 10492a17138dSJerry Jelinek cp = "service exited with a configuration error"; 10502a17138dSJerry Jelinek break; 10512a17138dSJerry Jelinek case RSTOP_ERR_EXIT: 10522a17138dSJerry Jelinek re = RERR_RESTART; 10532a17138dSJerry Jelinek reason = restarter_str_ct_ev_exit; 10542a17138dSJerry Jelinek cp = "service exited with an error"; 10552a17138dSJerry Jelinek break; 10567c478bd9Sstevel@tonic-gate case RSTOP_CORE: 10577c478bd9Sstevel@tonic-gate re = RERR_FAULT; 1058f6e214c7SGavin Maltby reason = restarter_str_ct_ev_core; 10597c478bd9Sstevel@tonic-gate cp = "process dumped core"; 10607c478bd9Sstevel@tonic-gate break; 10617c478bd9Sstevel@tonic-gate case RSTOP_SIGNAL: 10627c478bd9Sstevel@tonic-gate re = RERR_FAULT; 1063f6e214c7SGavin Maltby reason = restarter_str_ct_ev_signal; 10647c478bd9Sstevel@tonic-gate cp = "process received fatal signal from outside the service"; 10657c478bd9Sstevel@tonic-gate break; 10667c478bd9Sstevel@tonic-gate case RSTOP_HWERR: 10677c478bd9Sstevel@tonic-gate re = RERR_FAULT; 1068f6e214c7SGavin Maltby reason = restarter_str_ct_ev_hwerr; 10697c478bd9Sstevel@tonic-gate cp = "process killed due to uncorrectable hardware error"; 10707c478bd9Sstevel@tonic-gate break; 10717c478bd9Sstevel@tonic-gate case RSTOP_DEPENDENCY: 10727c478bd9Sstevel@tonic-gate re = RERR_RESTART; 1073f6e214c7SGavin Maltby reason = restarter_str_dependency_activity; 10747c478bd9Sstevel@tonic-gate cp = "dependency activity requires stop"; 10757c478bd9Sstevel@tonic-gate break; 10767c478bd9Sstevel@tonic-gate case RSTOP_DISABLE: 10777c478bd9Sstevel@tonic-gate re = RERR_RESTART; 1078f6e214c7SGavin Maltby reason = restarter_str_disable_request; 10797c478bd9Sstevel@tonic-gate cp = "service disabled"; 10807c478bd9Sstevel@tonic-gate break; 10817c478bd9Sstevel@tonic-gate case RSTOP_RESTART: 10827c478bd9Sstevel@tonic-gate re = RERR_RESTART; 1083f6e214c7SGavin Maltby reason = restarter_str_restart_request; 10847c478bd9Sstevel@tonic-gate cp = "service restarting"; 10857c478bd9Sstevel@tonic-gate break; 10867c478bd9Sstevel@tonic-gate default: 10877c478bd9Sstevel@tonic-gate #ifndef NDEBUG 10887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Unknown cause %d at %s:%d.\n", 10897c478bd9Sstevel@tonic-gate cause, __FILE__, __LINE__); 10907c478bd9Sstevel@tonic-gate #endif 10917c478bd9Sstevel@tonic-gate abort(); 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate /* Services in the disabled and maintenance state are ignored */ 10957c478bd9Sstevel@tonic-gate if (inst->ri_i.i_state == RESTARTER_STATE_MAINT || 10967c478bd9Sstevel@tonic-gate inst->ri_i.i_state == RESTARTER_STATE_DISABLED) { 10977c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, 10987c478bd9Sstevel@tonic-gate "%s: stop_instance -> is maint/disabled\n", 10997c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 11007c478bd9Sstevel@tonic-gate return (0); 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate 11037c478bd9Sstevel@tonic-gate /* Already stopped instances are left alone */ 11047c478bd9Sstevel@tonic-gate if (instance_started(inst) == 0) { 11057c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: %s is already stopped.\n", 11067c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 11077c478bd9Sstevel@tonic-gate return (0); 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate if (instance_in_transition(inst)) { 11117c478bd9Sstevel@tonic-gate /* requeue event by returning -1 */ 11127c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, 11137c478bd9Sstevel@tonic-gate "Restarter: Not stopping %s, in transition.\n", 11147c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 11157c478bd9Sstevel@tonic-gate return (-1); 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate log_instance(inst, B_TRUE, "Stopping because %s.", cp); 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate log_framework(re == RERR_FAULT ? LOG_INFO : LOG_DEBUG, 11217c478bd9Sstevel@tonic-gate "%s: Instance stopping because %s.\n", inst->ri_i.i_fmri, cp); 11227c478bd9Sstevel@tonic-gate 11232a17138dSJerry Jelinek if (instance_is_wait_style(inst) && 11242a17138dSJerry Jelinek (cause == RSTOP_EXIT || 11252a17138dSJerry Jelinek cause == RSTOP_ERR_CFG || 11262a17138dSJerry Jelinek cause == RSTOP_ERR_EXIT)) { 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * No need to stop instance, as child has exited; remove 11297c478bd9Sstevel@tonic-gate * contract and move the instance to the offline state. 11307c478bd9Sstevel@tonic-gate */ 11317c478bd9Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, 11327c478bd9Sstevel@tonic-gate inst, inst->ri_i.i_state, RESTARTER_STATE_OFFLINE, re, 1133f6e214c7SGavin Maltby reason)) { 11347c478bd9Sstevel@tonic-gate case 0: 11357c478bd9Sstevel@tonic-gate case ECONNRESET: 11367c478bd9Sstevel@tonic-gate break; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate default: 11397c478bd9Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate 11422a17138dSJerry Jelinek if (cause == RSTOP_ERR_EXIT) { 11432a17138dSJerry Jelinek /* 11442a17138dSJerry Jelinek * The RSTOP_ERR_EXIT cause is set via the 11452a17138dSJerry Jelinek * wait_thread -> wait_remove code path when we have 11462a17138dSJerry Jelinek * a "wait" style svc that exited with an error. If 11472a17138dSJerry Jelinek * the svc is failing too quickly, we throttle it so 11482a17138dSJerry Jelinek * that we don't restart it more than once/second. 11492a17138dSJerry Jelinek * Since we know we're running in the wait thread its 11502a17138dSJerry Jelinek * ok to throttle it right here. 11512a17138dSJerry Jelinek */ 11522a17138dSJerry Jelinek (void) update_fault_count(inst, FAULT_COUNT_INCR); 11532a17138dSJerry Jelinek if (method_rate_critical(inst)) { 11542a17138dSJerry Jelinek log_instance(inst, B_TRUE, "Failing too " 11552a17138dSJerry Jelinek "quickly, throttling."); 11562a17138dSJerry Jelinek (void) sleep(WT_SVC_ERR_THROTTLE); 11572a17138dSJerry Jelinek } 11582a17138dSJerry Jelinek } else { 11597c478bd9Sstevel@tonic-gate (void) update_fault_count(inst, FAULT_COUNT_RESET); 1160c238c833SSean Wilcox reset_start_times(inst); 11612a17138dSJerry Jelinek } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid != 0) { 11647c478bd9Sstevel@tonic-gate inst->ri_m_inst = 11657c478bd9Sstevel@tonic-gate safe_scf_instance_create(local_handle); 11667c478bd9Sstevel@tonic-gate inst->ri_mi_deleted = B_FALSE; 11677c478bd9Sstevel@tonic-gate 11687c478bd9Sstevel@tonic-gate libscf_reget_instance(inst); 11697c478bd9Sstevel@tonic-gate method_remove_contract(inst, B_TRUE, B_TRUE); 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate scf_instance_destroy(inst->ri_m_inst); 11727c478bd9Sstevel@tonic-gate inst->ri_m_inst = NULL; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, 11767c478bd9Sstevel@tonic-gate inst, inst->ri_i.i_next_state, RESTARTER_STATE_NONE, re, 1177f6e214c7SGavin Maltby reason)) { 11787c478bd9Sstevel@tonic-gate case 0: 11797c478bd9Sstevel@tonic-gate case ECONNRESET: 11807c478bd9Sstevel@tonic-gate break; 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate default: 11837c478bd9Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 11847c478bd9Sstevel@tonic-gate } 11857c478bd9Sstevel@tonic-gate 11862a17138dSJerry Jelinek if (cause != RSTOP_ERR_CFG) 11877c478bd9Sstevel@tonic-gate return (0); 118863c7f71bSrm88369 } else if (instance_is_wait_style(inst) && re == RERR_RESTART) { 118963c7f71bSrm88369 /* 119063c7f71bSrm88369 * Stopping a wait service through means other than the pid 119163c7f71bSrm88369 * exiting should keep wait_thread() from restarting the 119263c7f71bSrm88369 * service, by removing it from the wait list. 119363c7f71bSrm88369 * We cannot remove it right now otherwise the process will 119463c7f71bSrm88369 * end up <defunct> so mark it to be ignored. 119563c7f71bSrm88369 */ 119663c7f71bSrm88369 wait_ignore_by_fmri(inst->ri_i.i_fmri); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11992a17138dSJerry Jelinek /* 12002a17138dSJerry Jelinek * There are some configuration errors which we cannot detect until we 12012a17138dSJerry Jelinek * try to run the method. For example, see exec_method() where the 12022a17138dSJerry Jelinek * restarter_set_method_context() call can return SMF_EXIT_ERR_CONFIG 12032a17138dSJerry Jelinek * in several cases. If this happens for a "wait-style" svc, 12042a17138dSJerry Jelinek * wait_remove() sets the cause as RSTOP_ERR_CFG so that we can detect 12052a17138dSJerry Jelinek * the configuration error and go into maintenance, even though it is 12062a17138dSJerry Jelinek * a "wait-style" svc. 12072a17138dSJerry Jelinek */ 12082a17138dSJerry Jelinek if (cause == RSTOP_ERR_CFG) 12092a17138dSJerry Jelinek new_state = RESTARTER_STATE_MAINT; 12102a17138dSJerry Jelinek else 12112a17138dSJerry Jelinek new_state = inst->ri_i.i_enabled ? 12122a17138dSJerry Jelinek RESTARTER_STATE_OFFLINE : RESTARTER_STATE_DISABLED; 12132a17138dSJerry Jelinek 12147c478bd9Sstevel@tonic-gate switch (err = restarter_instance_update_states(local_handle, inst, 12152a17138dSJerry Jelinek inst->ri_i.i_state, new_state, RERR_NONE, reason)) { 12167c478bd9Sstevel@tonic-gate case 0: 12177c478bd9Sstevel@tonic-gate case ECONNRESET: 12187c478bd9Sstevel@tonic-gate break; 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate default: 12217c478bd9Sstevel@tonic-gate bad_error("restarter_instance_update_states", err); 12227c478bd9Sstevel@tonic-gate } 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate info = startd_zalloc(sizeof (fork_info_t)); 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate info->sf_id = inst->ri_id; 12277c478bd9Sstevel@tonic-gate info->sf_method_type = METHOD_STOP; 12287c478bd9Sstevel@tonic-gate info->sf_event_type = re; 1229f6e214c7SGavin Maltby info->sf_reason = reason; 12307c478bd9Sstevel@tonic-gate inst->ri_method_thread = startd_thread_create(method_thread, info); 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate return (0); 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate 12357c478bd9Sstevel@tonic-gate /* 12367c478bd9Sstevel@tonic-gate * Returns 12377c478bd9Sstevel@tonic-gate * ENOENT - fmri is not in instance_list 12387c478bd9Sstevel@tonic-gate * 0 - success 12397c478bd9Sstevel@tonic-gate * ECONNRESET - success, though handle was rebound 12407c478bd9Sstevel@tonic-gate * -1 - instance is in transition 12417c478bd9Sstevel@tonic-gate */ 12427c478bd9Sstevel@tonic-gate int 12437c478bd9Sstevel@tonic-gate stop_instance_fmri(scf_handle_t *h, const char *fmri, uint_t flags) 12447c478bd9Sstevel@tonic-gate { 12457c478bd9Sstevel@tonic-gate restarter_inst_t *rip; 12467c478bd9Sstevel@tonic-gate int r; 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate rip = inst_lookup_by_name(fmri); 12497c478bd9Sstevel@tonic-gate if (rip == NULL) 12507c478bd9Sstevel@tonic-gate return (ENOENT); 12517c478bd9Sstevel@tonic-gate 12527c478bd9Sstevel@tonic-gate r = stop_instance(h, rip, flags); 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_lock); 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate return (r); 12577c478bd9Sstevel@tonic-gate } 12587c478bd9Sstevel@tonic-gate 12597c478bd9Sstevel@tonic-gate static void 12607c478bd9Sstevel@tonic-gate unmaintain_instance(scf_handle_t *h, restarter_inst_t *rip, 12617c478bd9Sstevel@tonic-gate unmaint_cause_t cause) 12627c478bd9Sstevel@tonic-gate { 12637c478bd9Sstevel@tonic-gate ctid_t ctid; 12647c478bd9Sstevel@tonic-gate scf_instance_t *inst; 12657c478bd9Sstevel@tonic-gate int r; 12667c478bd9Sstevel@tonic-gate uint_t tries = 0, msecs = ALLOC_DELAY; 12677c478bd9Sstevel@tonic-gate const char *cp; 1268f6e214c7SGavin Maltby restarter_str_t reason; 12697c478bd9Sstevel@tonic-gate 127053f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&rip->ri_lock)); 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate if (rip->ri_i.i_state != RESTARTER_STATE_MAINT) { 12737c478bd9Sstevel@tonic-gate log_error(LOG_DEBUG, "Restarter: " 12747c478bd9Sstevel@tonic-gate "Ignoring maintenance off command because %s is not in the " 12757c478bd9Sstevel@tonic-gate "maintenance state.\n", rip->ri_i.i_fmri); 12767c478bd9Sstevel@tonic-gate return; 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate switch (cause) { 12807c478bd9Sstevel@tonic-gate case RUNMAINT_CLEAR: 12817c478bd9Sstevel@tonic-gate cp = "clear requested"; 1282f6e214c7SGavin Maltby reason = restarter_str_clear_request; 12837c478bd9Sstevel@tonic-gate break; 12847c478bd9Sstevel@tonic-gate case RUNMAINT_DISABLE: 12857c478bd9Sstevel@tonic-gate cp = "disable requested"; 1286f6e214c7SGavin Maltby reason = restarter_str_disable_request; 12877c478bd9Sstevel@tonic-gate break; 12887c478bd9Sstevel@tonic-gate default: 12897c478bd9Sstevel@tonic-gate #ifndef NDEBUG 12907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Uncaught case for %d at %s:%d.\n", 12917c478bd9Sstevel@tonic-gate cause, __FILE__, __LINE__); 12927c478bd9Sstevel@tonic-gate #endif 12937c478bd9Sstevel@tonic-gate abort(); 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate log_instance(rip, B_TRUE, "Leaving maintenance because %s.", 12977c478bd9Sstevel@tonic-gate cp); 12987c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance leaving maintenance because " 12997c478bd9Sstevel@tonic-gate "%s.\n", rip->ri_i.i_fmri, cp); 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, RESTARTER_STATE_UNINIT, 1302f6e214c7SGavin Maltby RESTARTER_STATE_NONE, RERR_RESTART, reason); 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* 13057c478bd9Sstevel@tonic-gate * If we did ADMIN_MAINT_ON_IMMEDIATE, then there might still be 13067c478bd9Sstevel@tonic-gate * a primary contract. 13077c478bd9Sstevel@tonic-gate */ 13087c478bd9Sstevel@tonic-gate if (rip->ri_i.i_primary_ctid == 0) 13097c478bd9Sstevel@tonic-gate return; 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate ctid = rip->ri_i.i_primary_ctid; 13127c478bd9Sstevel@tonic-gate contract_abandon(ctid); 13137c478bd9Sstevel@tonic-gate rip->ri_i.i_primary_ctid = 0; 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate rep_retry: 13167c478bd9Sstevel@tonic-gate switch (r = libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst)) { 13177c478bd9Sstevel@tonic-gate case 0: 13187c478bd9Sstevel@tonic-gate break; 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate case ECONNABORTED: 13217c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 13227c478bd9Sstevel@tonic-gate goto rep_retry; 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate case ENOENT: 13257c478bd9Sstevel@tonic-gate /* Must have been deleted. */ 13267c478bd9Sstevel@tonic-gate return; 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate case EINVAL: 13297c478bd9Sstevel@tonic-gate case ENOTSUP: 13307c478bd9Sstevel@tonic-gate default: 13317c478bd9Sstevel@tonic-gate bad_error("libscf_handle_rebind", r); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate again: 13357c478bd9Sstevel@tonic-gate r = restarter_remove_contract(inst, ctid, RESTARTER_CONTRACT_PRIMARY); 13367c478bd9Sstevel@tonic-gate switch (r) { 13377c478bd9Sstevel@tonic-gate case 0: 13387c478bd9Sstevel@tonic-gate break; 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate case ENOMEM: 13417c478bd9Sstevel@tonic-gate ++tries; 13427c478bd9Sstevel@tonic-gate if (tries < ALLOC_RETRY) { 13437c478bd9Sstevel@tonic-gate (void) poll(NULL, 0, msecs); 13447c478bd9Sstevel@tonic-gate msecs *= ALLOC_DELAY_MULT; 13457c478bd9Sstevel@tonic-gate goto again; 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate 13487c478bd9Sstevel@tonic-gate uu_die("Insufficient memory.\n"); 13497c478bd9Sstevel@tonic-gate /* NOTREACHED */ 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate case ECONNABORTED: 13527c478bd9Sstevel@tonic-gate scf_instance_destroy(inst); 13537c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 13547c478bd9Sstevel@tonic-gate goto rep_retry; 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate case ECANCELED: 13577c478bd9Sstevel@tonic-gate break; 13587c478bd9Sstevel@tonic-gate 13597c478bd9Sstevel@tonic-gate case EPERM: 13607c478bd9Sstevel@tonic-gate case EACCES: 13617c478bd9Sstevel@tonic-gate case EROFS: 13627c478bd9Sstevel@tonic-gate log_error(LOG_INFO, 13637c478bd9Sstevel@tonic-gate "Could not remove contract id %lu for %s (%s).\n", ctid, 13647c478bd9Sstevel@tonic-gate rip->ri_i.i_fmri, strerror(r)); 13657c478bd9Sstevel@tonic-gate break; 13667c478bd9Sstevel@tonic-gate 13677c478bd9Sstevel@tonic-gate case EINVAL: 13687c478bd9Sstevel@tonic-gate case EBADF: 13697c478bd9Sstevel@tonic-gate default: 13707c478bd9Sstevel@tonic-gate bad_error("restarter_remove_contract", r); 13717c478bd9Sstevel@tonic-gate } 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate scf_instance_destroy(inst); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate /* 13777c478bd9Sstevel@tonic-gate * enable_inst() 13787c478bd9Sstevel@tonic-gate * Set inst->ri_i.i_enabled. Expects 'e' to be _ENABLE, _DISABLE, or 13797c478bd9Sstevel@tonic-gate * _ADMIN_DISABLE. If the event is _ENABLE and inst is uninitialized or 13807c478bd9Sstevel@tonic-gate * disabled, move it to offline. If the event is _DISABLE or 13817c478bd9Sstevel@tonic-gate * _ADMIN_DISABLE, make sure inst will move to disabled. 13827c478bd9Sstevel@tonic-gate * 13837c478bd9Sstevel@tonic-gate * Returns 13847c478bd9Sstevel@tonic-gate * 0 - success 13857c478bd9Sstevel@tonic-gate * ECONNRESET - h was rebound 13867c478bd9Sstevel@tonic-gate */ 13877c478bd9Sstevel@tonic-gate static int 1388f6e214c7SGavin Maltby enable_inst(scf_handle_t *h, restarter_inst_t *inst, 1389f6e214c7SGavin Maltby restarter_instance_qentry_t *riq) 13907c478bd9Sstevel@tonic-gate { 13917c478bd9Sstevel@tonic-gate restarter_instance_state_t state; 1392f6e214c7SGavin Maltby restarter_event_type_t e = riq->riq_type; 1393f6e214c7SGavin Maltby restarter_str_t reason = restarter_str_per_configuration; 13947c478bd9Sstevel@tonic-gate int r; 13957c478bd9Sstevel@tonic-gate 139653f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 13977c478bd9Sstevel@tonic-gate assert(e == RESTARTER_EVENT_TYPE_ADMIN_DISABLE || 13987c478bd9Sstevel@tonic-gate e == RESTARTER_EVENT_TYPE_DISABLE || 13997c478bd9Sstevel@tonic-gate e == RESTARTER_EVENT_TYPE_ENABLE); 14007c478bd9Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate state = inst->ri_i.i_state; 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate if (e == RESTARTER_EVENT_TYPE_ENABLE) { 14057c478bd9Sstevel@tonic-gate inst->ri_i.i_enabled = 1; 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate if (state == RESTARTER_STATE_UNINIT || 14087c478bd9Sstevel@tonic-gate state == RESTARTER_STATE_DISABLED) { 14097c478bd9Sstevel@tonic-gate /* 14107c478bd9Sstevel@tonic-gate * B_FALSE: Don't log an error if the log_instance() 14117c478bd9Sstevel@tonic-gate * fails because it will fail on the miniroot before 14127c478bd9Sstevel@tonic-gate * install-discovery runs. 14137c478bd9Sstevel@tonic-gate */ 14147c478bd9Sstevel@tonic-gate log_instance(inst, B_FALSE, "Enabled."); 14157c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance enabled.\n", 14167c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 1417f6e214c7SGavin Maltby 1418f6e214c7SGavin Maltby /* 1419f6e214c7SGavin Maltby * If we are coming from DISABLED, it was obviously an 1420f6e214c7SGavin Maltby * enable request. If we are coming from UNINIT, it may 1421f6e214c7SGavin Maltby * have been a sevice in MAINT that was cleared. 1422f6e214c7SGavin Maltby */ 1423f6e214c7SGavin Maltby if (riq->riq_reason == restarter_str_clear_request) 1424f6e214c7SGavin Maltby reason = restarter_str_clear_request; 1425f6e214c7SGavin Maltby else if (state == RESTARTER_STATE_DISABLED) 1426f6e214c7SGavin Maltby reason = restarter_str_enable_request; 14277c478bd9Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, 14287c478bd9Sstevel@tonic-gate RESTARTER_STATE_OFFLINE, RESTARTER_STATE_NONE, 1429f6e214c7SGavin Maltby RERR_NONE, reason); 14307c478bd9Sstevel@tonic-gate } else { 14317c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: " 14327c478bd9Sstevel@tonic-gate "Not changing state of %s for enable command.\n", 14337c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate } else { 14367c478bd9Sstevel@tonic-gate inst->ri_i.i_enabled = 0; 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate switch (state) { 14397c478bd9Sstevel@tonic-gate case RESTARTER_STATE_ONLINE: 14407c478bd9Sstevel@tonic-gate case RESTARTER_STATE_DEGRADED: 14417c478bd9Sstevel@tonic-gate r = stop_instance(h, inst, RSTOP_DISABLE); 14427c478bd9Sstevel@tonic-gate return (r == ECONNRESET ? 0 : r); 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate case RESTARTER_STATE_OFFLINE: 14457c478bd9Sstevel@tonic-gate case RESTARTER_STATE_UNINIT: 14467c478bd9Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid != 0) { 14477c478bd9Sstevel@tonic-gate inst->ri_m_inst = safe_scf_instance_create(h); 14487c478bd9Sstevel@tonic-gate inst->ri_mi_deleted = B_FALSE; 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate libscf_reget_instance(inst); 14517c478bd9Sstevel@tonic-gate method_remove_contract(inst, B_TRUE, B_TRUE); 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate scf_instance_destroy(inst->ri_m_inst); 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate /* B_FALSE: See log_instance(..., "Enabled."); above */ 14567c478bd9Sstevel@tonic-gate log_instance(inst, B_FALSE, "Disabled."); 14577c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance disabled.\n", 14587c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 1459f6e214c7SGavin Maltby 1460f6e214c7SGavin Maltby /* 1461f6e214c7SGavin Maltby * If we are coming from OFFLINE, it was obviously a 1462f6e214c7SGavin Maltby * disable request. But if we are coming from 1463f6e214c7SGavin Maltby * UNINIT, it may have been a disable request for a 1464f6e214c7SGavin Maltby * service in MAINT. 1465f6e214c7SGavin Maltby */ 1466f6e214c7SGavin Maltby if (riq->riq_reason == restarter_str_disable_request || 1467f6e214c7SGavin Maltby state == RESTARTER_STATE_OFFLINE) 1468f6e214c7SGavin Maltby reason = restarter_str_disable_request; 14697c478bd9Sstevel@tonic-gate (void) restarter_instance_update_states(h, inst, 14707c478bd9Sstevel@tonic-gate RESTARTER_STATE_DISABLED, RESTARTER_STATE_NONE, 1471f6e214c7SGavin Maltby RERR_RESTART, reason); 14727c478bd9Sstevel@tonic-gate return (0); 14737c478bd9Sstevel@tonic-gate 14747c478bd9Sstevel@tonic-gate case RESTARTER_STATE_DISABLED: 14757c478bd9Sstevel@tonic-gate break; 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate case RESTARTER_STATE_MAINT: 14787c478bd9Sstevel@tonic-gate /* 14797c478bd9Sstevel@tonic-gate * We only want to pull the instance out of maintenance 14807c478bd9Sstevel@tonic-gate * if the disable is on adminstrative request. The 14817c478bd9Sstevel@tonic-gate * graph engine sends _DISABLE events whenever a 14827c478bd9Sstevel@tonic-gate * service isn't in the disabled state, and we don't 14837c478bd9Sstevel@tonic-gate * want to pull the service out of maintenance if, 14847c478bd9Sstevel@tonic-gate * for example, it is there due to a dependency cycle. 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate if (e == RESTARTER_EVENT_TYPE_ADMIN_DISABLE) 14877c478bd9Sstevel@tonic-gate unmaintain_instance(h, inst, RUNMAINT_DISABLE); 14887c478bd9Sstevel@tonic-gate break; 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate default: 14917c478bd9Sstevel@tonic-gate #ifndef NDEBUG 14927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Restarter instance %s has " 14937c478bd9Sstevel@tonic-gate "unknown state %d.\n", inst->ri_i.i_fmri, state); 14947c478bd9Sstevel@tonic-gate #endif 14957c478bd9Sstevel@tonic-gate abort(); 14967c478bd9Sstevel@tonic-gate } 14977c478bd9Sstevel@tonic-gate } 14987c478bd9Sstevel@tonic-gate 14997c478bd9Sstevel@tonic-gate return (0); 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate 15027c478bd9Sstevel@tonic-gate static void 1503f6e214c7SGavin Maltby start_instance(scf_handle_t *local_handle, restarter_inst_t *inst, 1504f6e214c7SGavin Maltby int32_t reason) 15057c478bd9Sstevel@tonic-gate { 15067c478bd9Sstevel@tonic-gate fork_info_t *info; 1507f6e214c7SGavin Maltby restarter_str_t new_reason; 15087c478bd9Sstevel@tonic-gate 150953f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 15107c478bd9Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 15117c478bd9Sstevel@tonic-gate assert(inst->ri_method_thread == 0); 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: trying to start instance\n", 15147c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 15157c478bd9Sstevel@tonic-gate 1516f6e214c7SGavin Maltby /* 1517f6e214c7SGavin Maltby * We want to keep the original reason for restarts and clear actions 1518f6e214c7SGavin Maltby */ 1519f6e214c7SGavin Maltby switch (reason) { 1520f6e214c7SGavin Maltby case restarter_str_restart_request: 1521f6e214c7SGavin Maltby case restarter_str_clear_request: 1522f6e214c7SGavin Maltby new_reason = reason; 1523f6e214c7SGavin Maltby break; 1524f6e214c7SGavin Maltby default: 1525f6e214c7SGavin Maltby new_reason = restarter_str_dependencies_satisfied; 1526f6e214c7SGavin Maltby } 1527f6e214c7SGavin Maltby 15287c478bd9Sstevel@tonic-gate /* Services in the disabled and maintenance state are ignored */ 15297c478bd9Sstevel@tonic-gate if (inst->ri_i.i_state == RESTARTER_STATE_MAINT || 15307c478bd9Sstevel@tonic-gate inst->ri_i.i_state == RESTARTER_STATE_DISABLED || 15317c478bd9Sstevel@tonic-gate inst->ri_i.i_enabled == 0) { 15327c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, 15337c478bd9Sstevel@tonic-gate "%s: start_instance -> is maint/disabled\n", 15347c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 15357c478bd9Sstevel@tonic-gate return; 15367c478bd9Sstevel@tonic-gate } 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate /* Already started instances are left alone */ 15397c478bd9Sstevel@tonic-gate if (instance_started(inst) == 1) { 15407c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, 15417c478bd9Sstevel@tonic-gate "%s: start_instance -> is already started\n", 15427c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 15437c478bd9Sstevel@tonic-gate return; 15447c478bd9Sstevel@tonic-gate } 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: starting instance.\n", inst->ri_i.i_fmri); 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate (void) restarter_instance_update_states(local_handle, inst, 1549f6e214c7SGavin Maltby inst->ri_i.i_state, RESTARTER_STATE_ONLINE, RERR_NONE, new_reason); 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate info = startd_zalloc(sizeof (fork_info_t)); 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate info->sf_id = inst->ri_id; 15547c478bd9Sstevel@tonic-gate info->sf_method_type = METHOD_START; 15557c478bd9Sstevel@tonic-gate info->sf_event_type = RERR_NONE; 1556f6e214c7SGavin Maltby info->sf_reason = new_reason; 15577c478bd9Sstevel@tonic-gate inst->ri_method_thread = startd_thread_create(method_thread, info); 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate 1560eb1a3463STruong Nguyen static int 1561eb1a3463STruong Nguyen event_from_tty(scf_handle_t *h, restarter_inst_t *rip) 1562eb1a3463STruong Nguyen { 1563eb1a3463STruong Nguyen scf_instance_t *inst; 1564eb1a3463STruong Nguyen int ret = 0; 1565eb1a3463STruong Nguyen 1566eb1a3463STruong Nguyen if (libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst)) 1567eb1a3463STruong Nguyen return (-1); 1568eb1a3463STruong Nguyen 1569eb1a3463STruong Nguyen ret = restarter_inst_ractions_from_tty(inst); 1570eb1a3463STruong Nguyen 1571eb1a3463STruong Nguyen scf_instance_destroy(inst); 1572eb1a3463STruong Nguyen return (ret); 1573eb1a3463STruong Nguyen } 1574eb1a3463STruong Nguyen 1575*ac0324d2SJerry Jelinek static boolean_t 1576*ac0324d2SJerry Jelinek restart_dump(scf_handle_t *h, restarter_inst_t *rip) 1577*ac0324d2SJerry Jelinek { 1578*ac0324d2SJerry Jelinek scf_instance_t *inst; 1579*ac0324d2SJerry Jelinek boolean_t ret = B_FALSE; 1580*ac0324d2SJerry Jelinek 1581*ac0324d2SJerry Jelinek if (libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst)) 1582*ac0324d2SJerry Jelinek return (-1); 1583*ac0324d2SJerry Jelinek 1584*ac0324d2SJerry Jelinek if (restarter_inst_dump(inst) == 1) 1585*ac0324d2SJerry Jelinek ret = B_TRUE; 1586*ac0324d2SJerry Jelinek 1587*ac0324d2SJerry Jelinek scf_instance_destroy(inst); 1588*ac0324d2SJerry Jelinek return (ret); 1589*ac0324d2SJerry Jelinek } 1590*ac0324d2SJerry Jelinek 15917c478bd9Sstevel@tonic-gate static void 15927c478bd9Sstevel@tonic-gate maintain_instance(scf_handle_t *h, restarter_inst_t *rip, int immediate, 1593f6e214c7SGavin Maltby restarter_str_t reason) 15947c478bd9Sstevel@tonic-gate { 15957c478bd9Sstevel@tonic-gate fork_info_t *info; 1596eb1a3463STruong Nguyen scf_instance_t *scf_inst = NULL; 15977c478bd9Sstevel@tonic-gate 159853f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&rip->ri_lock)); 1599f6e214c7SGavin Maltby assert(reason != restarter_str_none); 16007c478bd9Sstevel@tonic-gate assert(rip->ri_method_thread == 0); 16017c478bd9Sstevel@tonic-gate 1602f6e214c7SGavin Maltby log_instance(rip, B_TRUE, "Stopping for maintenance due to %s.", 1603f6e214c7SGavin Maltby restarter_get_str_short(reason)); 16047c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: stopping for maintenance due to %s.\n", 1605f6e214c7SGavin Maltby rip->ri_i.i_fmri, restarter_get_str_short(reason)); 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate /* Services in the maintenance state are ignored */ 16087c478bd9Sstevel@tonic-gate if (rip->ri_i.i_state == RESTARTER_STATE_MAINT) { 16097c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, 16107c478bd9Sstevel@tonic-gate "%s: maintain_instance -> is already in maintenance\n", 16117c478bd9Sstevel@tonic-gate rip->ri_i.i_fmri); 16127c478bd9Sstevel@tonic-gate return; 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 1615eb1a3463STruong Nguyen /* 1616f6e214c7SGavin Maltby * If reason state is restarter_str_service_request and 1617eb1a3463STruong Nguyen * restarter_actions/auxiliary_fmri property is set with a valid fmri, 1618eb1a3463STruong Nguyen * copy the fmri to restarter/auxiliary_fmri so svcs -x can use. 1619eb1a3463STruong Nguyen */ 1620f6e214c7SGavin Maltby if (reason == restarter_str_service_request && 1621f6e214c7SGavin Maltby libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &scf_inst) == 0) { 1622eb1a3463STruong Nguyen if (restarter_inst_validate_ractions_aux_fmri(scf_inst) == 0) { 1623eb1a3463STruong Nguyen if (restarter_inst_set_aux_fmri(scf_inst)) 1624eb1a3463STruong Nguyen log_framework(LOG_DEBUG, "%s: " 1625eb1a3463STruong Nguyen "restarter_inst_set_aux_fmri failed: ", 1626eb1a3463STruong Nguyen rip->ri_i.i_fmri); 1627eb1a3463STruong Nguyen } else { 1628eb1a3463STruong Nguyen log_framework(LOG_DEBUG, "%s: " 1629eb1a3463STruong Nguyen "restarter_inst_validate_ractions_aux_fmri " 1630eb1a3463STruong Nguyen "failed: ", rip->ri_i.i_fmri); 1631eb1a3463STruong Nguyen 1632eb1a3463STruong Nguyen if (restarter_inst_reset_aux_fmri(scf_inst)) 1633eb1a3463STruong Nguyen log_framework(LOG_DEBUG, "%s: " 1634eb1a3463STruong Nguyen "restarter_inst_reset_aux_fmri failed: ", 1635eb1a3463STruong Nguyen rip->ri_i.i_fmri); 1636eb1a3463STruong Nguyen } 1637eb1a3463STruong Nguyen scf_instance_destroy(scf_inst); 1638eb1a3463STruong Nguyen } 1639eb1a3463STruong Nguyen 16407c478bd9Sstevel@tonic-gate if (immediate || !instance_started(rip)) { 16417c478bd9Sstevel@tonic-gate if (rip->ri_i.i_primary_ctid != 0) { 16427c478bd9Sstevel@tonic-gate rip->ri_m_inst = safe_scf_instance_create(h); 16437c478bd9Sstevel@tonic-gate rip->ri_mi_deleted = B_FALSE; 16447c478bd9Sstevel@tonic-gate 16457c478bd9Sstevel@tonic-gate libscf_reget_instance(rip); 16467c478bd9Sstevel@tonic-gate method_remove_contract(rip, B_TRUE, B_TRUE); 16477c478bd9Sstevel@tonic-gate 16487c478bd9Sstevel@tonic-gate scf_instance_destroy(rip->ri_m_inst); 16497c478bd9Sstevel@tonic-gate } 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, 16527c478bd9Sstevel@tonic-gate RESTARTER_STATE_MAINT, RESTARTER_STATE_NONE, RERR_RESTART, 1653f6e214c7SGavin Maltby reason); 16547c478bd9Sstevel@tonic-gate return; 16557c478bd9Sstevel@tonic-gate } 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, rip->ri_i.i_state, 1658f6e214c7SGavin Maltby RESTARTER_STATE_MAINT, RERR_NONE, reason); 16597c478bd9Sstevel@tonic-gate 166099b44c3bSlianep log_transition(rip, MAINT_REQUESTED); 166199b44c3bSlianep 16627c478bd9Sstevel@tonic-gate info = startd_zalloc(sizeof (*info)); 16637c478bd9Sstevel@tonic-gate info->sf_id = rip->ri_id; 16647c478bd9Sstevel@tonic-gate info->sf_method_type = METHOD_STOP; 16657c478bd9Sstevel@tonic-gate info->sf_event_type = RERR_RESTART; 1666f6e214c7SGavin Maltby info->sf_reason = reason; 16677c478bd9Sstevel@tonic-gate rip->ri_method_thread = startd_thread_create(method_thread, info); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate 16707c478bd9Sstevel@tonic-gate static void 16717c478bd9Sstevel@tonic-gate refresh_instance(scf_handle_t *h, restarter_inst_t *rip) 16727c478bd9Sstevel@tonic-gate { 16737c478bd9Sstevel@tonic-gate scf_instance_t *inst; 16747c478bd9Sstevel@tonic-gate scf_snapshot_t *snap; 16757c478bd9Sstevel@tonic-gate fork_info_t *info; 16767c478bd9Sstevel@tonic-gate int r; 16777c478bd9Sstevel@tonic-gate 167853f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&rip->ri_lock)); 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate log_instance(rip, B_TRUE, "Rereading configuration."); 16817c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: rereading configuration.\n", 16827c478bd9Sstevel@tonic-gate rip->ri_i.i_fmri); 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate rep_retry: 16857c478bd9Sstevel@tonic-gate r = libscf_fmri_get_instance(h, rip->ri_i.i_fmri, &inst); 16867c478bd9Sstevel@tonic-gate switch (r) { 16877c478bd9Sstevel@tonic-gate case 0: 16887c478bd9Sstevel@tonic-gate break; 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate case ECONNABORTED: 16917c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 16927c478bd9Sstevel@tonic-gate goto rep_retry; 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate case ENOENT: 16957c478bd9Sstevel@tonic-gate /* Must have been deleted. */ 16967c478bd9Sstevel@tonic-gate return; 16977c478bd9Sstevel@tonic-gate 16987c478bd9Sstevel@tonic-gate case EINVAL: 16997c478bd9Sstevel@tonic-gate case ENOTSUP: 17007c478bd9Sstevel@tonic-gate default: 17017c478bd9Sstevel@tonic-gate bad_error("libscf_fmri_get_instance", r); 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate snap = libscf_get_running_snapshot(inst); 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate r = libscf_get_startd_properties(inst, snap, &rip->ri_flags, 17077c478bd9Sstevel@tonic-gate &rip->ri_utmpx_prefix); 17087c478bd9Sstevel@tonic-gate switch (r) { 17097c478bd9Sstevel@tonic-gate case 0: 17107c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s is a %s-style service\n", 17117c478bd9Sstevel@tonic-gate rip->ri_i.i_fmri, service_style(rip->ri_flags)); 17127c478bd9Sstevel@tonic-gate break; 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate case ECONNABORTED: 17157c478bd9Sstevel@tonic-gate scf_instance_destroy(inst); 17167c478bd9Sstevel@tonic-gate scf_snapshot_destroy(snap); 17177c478bd9Sstevel@tonic-gate libscf_handle_rebind(h); 17187c478bd9Sstevel@tonic-gate goto rep_retry; 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate case ECANCELED: 17217c478bd9Sstevel@tonic-gate case ENOENT: 17227c478bd9Sstevel@tonic-gate /* Succeed in anticipation of REMOVE_INSTANCE. */ 17237c478bd9Sstevel@tonic-gate break; 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate default: 17267c478bd9Sstevel@tonic-gate bad_error("libscf_get_startd_properties", r); 17277c478bd9Sstevel@tonic-gate } 17287c478bd9Sstevel@tonic-gate 17297c478bd9Sstevel@tonic-gate if (instance_started(rip)) { 17307c478bd9Sstevel@tonic-gate /* Refresh does not change the state. */ 17317c478bd9Sstevel@tonic-gate (void) restarter_instance_update_states(h, rip, 1732f6e214c7SGavin Maltby rip->ri_i.i_state, rip->ri_i.i_state, RERR_NONE, 1733f6e214c7SGavin Maltby restarter_str_refresh); 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate info = startd_zalloc(sizeof (*info)); 17367c478bd9Sstevel@tonic-gate info->sf_id = rip->ri_id; 17377c478bd9Sstevel@tonic-gate info->sf_method_type = METHOD_REFRESH; 17387c478bd9Sstevel@tonic-gate info->sf_event_type = RERR_REFRESH; 1739f6e214c7SGavin Maltby info->sf_reason = NULL; 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate assert(rip->ri_method_thread == 0); 17427c478bd9Sstevel@tonic-gate rip->ri_method_thread = 17437c478bd9Sstevel@tonic-gate startd_thread_create(method_thread, info); 17447c478bd9Sstevel@tonic-gate } 17457c478bd9Sstevel@tonic-gate 17467c478bd9Sstevel@tonic-gate scf_snapshot_destroy(snap); 17477c478bd9Sstevel@tonic-gate scf_instance_destroy(inst); 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate 17507c478bd9Sstevel@tonic-gate const char *event_names[] = { "INVALID", "ADD_INSTANCE", "REMOVE_INSTANCE", 17517c478bd9Sstevel@tonic-gate "ENABLE", "DISABLE", "ADMIN_DEGRADED", "ADMIN_REFRESH", 17527c478bd9Sstevel@tonic-gate "ADMIN_RESTART", "ADMIN_MAINT_OFF", "ADMIN_MAINT_ON", 17537c478bd9Sstevel@tonic-gate "ADMIN_MAINT_ON_IMMEDIATE", "STOP", "START", "DEPENDENCY_CYCLE", 1754c238c833SSean Wilcox "INVALID_DEPENDENCY", "ADMIN_DISABLE", "STOP_RESET" 17557c478bd9Sstevel@tonic-gate }; 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate /* 17587c478bd9Sstevel@tonic-gate * void *restarter_process_events() 17597c478bd9Sstevel@tonic-gate * 17607c478bd9Sstevel@tonic-gate * Called in a separate thread to process the events on an instance's 17617c478bd9Sstevel@tonic-gate * queue. Empties the queue completely, and tries to keep the thread 17627c478bd9Sstevel@tonic-gate * around for a little while after the queue is empty to save on 17637c478bd9Sstevel@tonic-gate * startup costs. 17647c478bd9Sstevel@tonic-gate */ 17657c478bd9Sstevel@tonic-gate static void * 17667c478bd9Sstevel@tonic-gate restarter_process_events(void *arg) 17677c478bd9Sstevel@tonic-gate { 17687c478bd9Sstevel@tonic-gate scf_handle_t *h; 17697c478bd9Sstevel@tonic-gate restarter_instance_qentry_t *event; 17707c478bd9Sstevel@tonic-gate restarter_inst_t *rip; 17717c478bd9Sstevel@tonic-gate char *fmri = (char *)arg; 17727c478bd9Sstevel@tonic-gate struct timespec to; 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate assert(fmri != NULL); 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate /* grab the queue lock */ 17797c478bd9Sstevel@tonic-gate rip = inst_lookup_queue(fmri); 17807c478bd9Sstevel@tonic-gate if (rip == NULL) 17817c478bd9Sstevel@tonic-gate goto out; 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate again: 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate while ((event = uu_list_first(rip->ri_queue)) != NULL) { 17867c478bd9Sstevel@tonic-gate restarter_inst_t *inst; 17877c478bd9Sstevel@tonic-gate 17887c478bd9Sstevel@tonic-gate /* drop the queue lock */ 17897c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate /* 17927c478bd9Sstevel@tonic-gate * Grab the inst lock -- this waits until any outstanding 17937c478bd9Sstevel@tonic-gate * method finishes running. 17947c478bd9Sstevel@tonic-gate */ 17957c478bd9Sstevel@tonic-gate inst = inst_lookup_by_name(fmri); 17967c478bd9Sstevel@tonic-gate if (inst == NULL) { 17977c478bd9Sstevel@tonic-gate /* Getting deleted in the middle isn't an error. */ 17987c478bd9Sstevel@tonic-gate goto cont; 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate /* process the event */ 18047c478bd9Sstevel@tonic-gate switch (event->riq_type) { 18057c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ENABLE: 18067c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_DISABLE: 1807f6e214c7SGavin Maltby (void) enable_inst(h, inst, event); 18087c478bd9Sstevel@tonic-gate break; 18097c478bd9Sstevel@tonic-gate 181016ba0facSSean Wilcox case RESTARTER_EVENT_TYPE_ADMIN_DISABLE: 1811f6e214c7SGavin Maltby if (enable_inst(h, inst, event) == 0) 181216ba0facSSean Wilcox reset_start_times(inst); 181316ba0facSSean Wilcox break; 181416ba0facSSean Wilcox 18157c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_REMOVE_INSTANCE: 18167c478bd9Sstevel@tonic-gate restarter_delete_inst(inst); 18177c478bd9Sstevel@tonic-gate inst = NULL; 18187c478bd9Sstevel@tonic-gate goto cont; 18197c478bd9Sstevel@tonic-gate 182016ba0facSSean Wilcox case RESTARTER_EVENT_TYPE_STOP_RESET: 182116ba0facSSean Wilcox reset_start_times(inst); 182216ba0facSSean Wilcox /* FALLTHROUGH */ 18237c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_STOP: 18247c478bd9Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_DEPENDENCY); 18257c478bd9Sstevel@tonic-gate break; 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_START: 1828f6e214c7SGavin Maltby start_instance(h, inst, event->riq_reason); 18297c478bd9Sstevel@tonic-gate break; 18307c478bd9Sstevel@tonic-gate 18317c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_DEPENDENCY_CYCLE: 1832f6e214c7SGavin Maltby maintain_instance(h, inst, 0, 1833f6e214c7SGavin Maltby restarter_str_dependency_cycle); 18347c478bd9Sstevel@tonic-gate break; 18357c478bd9Sstevel@tonic-gate 18367c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_INVALID_DEPENDENCY: 1837f6e214c7SGavin Maltby maintain_instance(h, inst, 0, 1838f6e214c7SGavin Maltby restarter_str_invalid_dependency); 18397c478bd9Sstevel@tonic-gate break; 18407c478bd9Sstevel@tonic-gate 18417c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON: 1842eb1a3463STruong Nguyen if (event_from_tty(h, inst) == 0) 1843eb1a3463STruong Nguyen maintain_instance(h, inst, 0, 1844f6e214c7SGavin Maltby restarter_str_service_request); 1845eb1a3463STruong Nguyen else 1846eb1a3463STruong Nguyen maintain_instance(h, inst, 0, 1847f6e214c7SGavin Maltby restarter_str_administrative_request); 18487c478bd9Sstevel@tonic-gate break; 18497c478bd9Sstevel@tonic-gate 18507c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE: 1851eb1a3463STruong Nguyen if (event_from_tty(h, inst) == 0) 1852eb1a3463STruong Nguyen maintain_instance(h, inst, 1, 1853f6e214c7SGavin Maltby restarter_str_service_request); 1854eb1a3463STruong Nguyen else 1855eb1a3463STruong Nguyen maintain_instance(h, inst, 1, 1856f6e214c7SGavin Maltby restarter_str_administrative_request); 18577c478bd9Sstevel@tonic-gate break; 18587c478bd9Sstevel@tonic-gate 18597c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF: 18607c478bd9Sstevel@tonic-gate unmaintain_instance(h, inst, RUNMAINT_CLEAR); 18618b55d351SSean Wilcox reset_start_times(inst); 18627c478bd9Sstevel@tonic-gate break; 18637c478bd9Sstevel@tonic-gate 18647c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_REFRESH: 18657c478bd9Sstevel@tonic-gate refresh_instance(h, inst); 18667c478bd9Sstevel@tonic-gate break; 18677c478bd9Sstevel@tonic-gate 18687c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED: 18697c478bd9Sstevel@tonic-gate log_framework(LOG_WARNING, "Restarter: " 18707c478bd9Sstevel@tonic-gate "%s command (for %s) unimplemented.\n", 18717c478bd9Sstevel@tonic-gate event_names[event->riq_type], inst->ri_i.i_fmri); 18727c478bd9Sstevel@tonic-gate break; 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_RESTART: 18757c478bd9Sstevel@tonic-gate if (!instance_started(inst)) { 18767c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "Restarter: " 18777c478bd9Sstevel@tonic-gate "Not restarting %s; not running.\n", 18787c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 18797c478bd9Sstevel@tonic-gate } else { 18807c478bd9Sstevel@tonic-gate /* 18817c478bd9Sstevel@tonic-gate * Stop the instance. If it can be restarted, 18827c478bd9Sstevel@tonic-gate * the graph engine will send a new event. 18837c478bd9Sstevel@tonic-gate */ 1884*ac0324d2SJerry Jelinek if (restart_dump(h, inst)) { 1885*ac0324d2SJerry Jelinek (void) contract_kill( 1886*ac0324d2SJerry Jelinek inst->ri_i.i_primary_ctid, SIGABRT, 1887*ac0324d2SJerry Jelinek inst->ri_i.i_fmri); 1888*ac0324d2SJerry Jelinek } else if (stop_instance(h, inst, 1889*ac0324d2SJerry Jelinek RSTOP_RESTART) == 0) { 189016ba0facSSean Wilcox reset_start_times(inst); 18917c478bd9Sstevel@tonic-gate } 1892*ac0324d2SJerry Jelinek } 18937c478bd9Sstevel@tonic-gate break; 18947c478bd9Sstevel@tonic-gate 18957c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADD_INSTANCE: 18967c478bd9Sstevel@tonic-gate default: 18977c478bd9Sstevel@tonic-gate #ifndef NDEBUG 18987c478bd9Sstevel@tonic-gate uu_warn("%s:%d: Bad restarter event %d. " 18997c478bd9Sstevel@tonic-gate "Aborting.\n", __FILE__, __LINE__, event->riq_type); 19007c478bd9Sstevel@tonic-gate #endif 19017c478bd9Sstevel@tonic-gate abort(); 19027c478bd9Sstevel@tonic-gate } 19037c478bd9Sstevel@tonic-gate 19047c478bd9Sstevel@tonic-gate assert(inst != NULL); 19057c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 19067c478bd9Sstevel@tonic-gate 19077c478bd9Sstevel@tonic-gate cont: 19087c478bd9Sstevel@tonic-gate /* grab the queue lock */ 19097c478bd9Sstevel@tonic-gate rip = inst_lookup_queue(fmri); 19107c478bd9Sstevel@tonic-gate if (rip == NULL) 19117c478bd9Sstevel@tonic-gate goto out; 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate /* delete the event */ 19147c478bd9Sstevel@tonic-gate uu_list_remove(rip->ri_queue, event); 19157c478bd9Sstevel@tonic-gate startd_free(event, sizeof (restarter_instance_qentry_t)); 19167c478bd9Sstevel@tonic-gate } 19177c478bd9Sstevel@tonic-gate 19187c478bd9Sstevel@tonic-gate assert(rip != NULL); 19197c478bd9Sstevel@tonic-gate 19207c478bd9Sstevel@tonic-gate /* 19217c478bd9Sstevel@tonic-gate * Try to preserve the thread for a little while for future use. 19227c478bd9Sstevel@tonic-gate */ 19237c478bd9Sstevel@tonic-gate to.tv_sec = 3; 19247c478bd9Sstevel@tonic-gate to.tv_nsec = 0; 19257c478bd9Sstevel@tonic-gate (void) pthread_cond_reltimedwait_np(&rip->ri_queue_cv, 19267c478bd9Sstevel@tonic-gate &rip->ri_queue_lock, &to); 19277c478bd9Sstevel@tonic-gate 19287c478bd9Sstevel@tonic-gate if (uu_list_first(rip->ri_queue) != NULL) 19297c478bd9Sstevel@tonic-gate goto again; 19307c478bd9Sstevel@tonic-gate 19317c478bd9Sstevel@tonic-gate rip->ri_queue_thread = 0; 19327c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 19333dd94f79SBryan Cantrill 19347c478bd9Sstevel@tonic-gate out: 19357c478bd9Sstevel@tonic-gate (void) scf_handle_unbind(h); 19367c478bd9Sstevel@tonic-gate scf_handle_destroy(h); 19377c478bd9Sstevel@tonic-gate free(fmri); 19387c478bd9Sstevel@tonic-gate return (NULL); 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate static int 19427c478bd9Sstevel@tonic-gate is_admin_event(restarter_event_type_t t) { 19437c478bd9Sstevel@tonic-gate 19447c478bd9Sstevel@tonic-gate switch (t) { 19457c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON: 19467c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_ON_IMMEDIATE: 19477c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_MAINT_OFF: 19487c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_REFRESH: 19497c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_DEGRADED: 19507c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADMIN_RESTART: 19517c478bd9Sstevel@tonic-gate return (1); 19527c478bd9Sstevel@tonic-gate default: 19537c478bd9Sstevel@tonic-gate return (0); 19547c478bd9Sstevel@tonic-gate } 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate 19577c478bd9Sstevel@tonic-gate static void 19587c478bd9Sstevel@tonic-gate restarter_queue_event(restarter_inst_t *ri, restarter_protocol_event_t *e) 19597c478bd9Sstevel@tonic-gate { 19607c478bd9Sstevel@tonic-gate restarter_instance_qentry_t *qe; 19617c478bd9Sstevel@tonic-gate int r; 19627c478bd9Sstevel@tonic-gate 196353f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&ri->ri_queue_lock)); 196453f3aea0SRoger A. Faulkner assert(!MUTEX_HELD(&ri->ri_lock)); 19657c478bd9Sstevel@tonic-gate 19667c478bd9Sstevel@tonic-gate qe = startd_zalloc(sizeof (restarter_instance_qentry_t)); 19677c478bd9Sstevel@tonic-gate qe->riq_type = e->rpe_type; 1968f6e214c7SGavin Maltby qe->riq_reason = e->rpe_reason; 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate uu_list_node_init(qe, &qe->riq_link, restarter_queue_pool); 19717c478bd9Sstevel@tonic-gate r = uu_list_insert_before(ri->ri_queue, NULL, qe); 19727c478bd9Sstevel@tonic-gate assert(r == 0); 19737c478bd9Sstevel@tonic-gate } 19747c478bd9Sstevel@tonic-gate 19757c478bd9Sstevel@tonic-gate /* 19767c478bd9Sstevel@tonic-gate * void *restarter_event_thread() 19777c478bd9Sstevel@tonic-gate * 19787c478bd9Sstevel@tonic-gate * Handle incoming graph events by placing them on a per-instance 19797c478bd9Sstevel@tonic-gate * queue. We can't lock the main part of the instance structure, so 19807c478bd9Sstevel@tonic-gate * just modify the seprarately locked event queue portion. 19817c478bd9Sstevel@tonic-gate */ 19827c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19837c478bd9Sstevel@tonic-gate static void * 19847c478bd9Sstevel@tonic-gate restarter_event_thread(void *unused) 19857c478bd9Sstevel@tonic-gate { 19867c478bd9Sstevel@tonic-gate scf_handle_t *h; 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate /* 19897c478bd9Sstevel@tonic-gate * This is a new thread, and thus, gets its own handle 19907c478bd9Sstevel@tonic-gate * to the repository. 19917c478bd9Sstevel@tonic-gate */ 19927c478bd9Sstevel@tonic-gate h = libscf_handle_create_bound_loop(); 19937c478bd9Sstevel@tonic-gate 19947c478bd9Sstevel@tonic-gate MUTEX_LOCK(&ru->restarter_update_lock); 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /*CONSTCOND*/ 19977c478bd9Sstevel@tonic-gate while (1) { 19987c478bd9Sstevel@tonic-gate restarter_protocol_event_t *e; 19997c478bd9Sstevel@tonic-gate 20007c478bd9Sstevel@tonic-gate while (ru->restarter_update_wakeup == 0) 20017c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&ru->restarter_update_cv, 20027c478bd9Sstevel@tonic-gate &ru->restarter_update_lock); 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate ru->restarter_update_wakeup = 0; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate while ((e = restarter_event_dequeue()) != NULL) { 20077c478bd9Sstevel@tonic-gate restarter_inst_t *rip; 20087c478bd9Sstevel@tonic-gate char *fmri; 20097c478bd9Sstevel@tonic-gate 20107c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&ru->restarter_update_lock); 20117c478bd9Sstevel@tonic-gate 20127c478bd9Sstevel@tonic-gate /* 20137c478bd9Sstevel@tonic-gate * ADD_INSTANCE is special: there's likely no 20147c478bd9Sstevel@tonic-gate * instance structure yet, so we need to handle the 20157c478bd9Sstevel@tonic-gate * addition synchronously. 20167c478bd9Sstevel@tonic-gate */ 20177c478bd9Sstevel@tonic-gate switch (e->rpe_type) { 20187c478bd9Sstevel@tonic-gate case RESTARTER_EVENT_TYPE_ADD_INSTANCE: 20197c478bd9Sstevel@tonic-gate if (restarter_insert_inst(h, e->rpe_inst) != 0) 20207c478bd9Sstevel@tonic-gate log_error(LOG_INFO, "Restarter: " 20217c478bd9Sstevel@tonic-gate "Could not add %s.\n", e->rpe_inst); 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate MUTEX_LOCK(&st->st_load_lock); 20247c478bd9Sstevel@tonic-gate if (--st->st_load_instances == 0) 20257c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast( 20267c478bd9Sstevel@tonic-gate &st->st_load_cv); 20277c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&st->st_load_lock); 20287c478bd9Sstevel@tonic-gate 20297c478bd9Sstevel@tonic-gate goto nolookup; 20307c478bd9Sstevel@tonic-gate } 20317c478bd9Sstevel@tonic-gate 20327c478bd9Sstevel@tonic-gate /* 20337c478bd9Sstevel@tonic-gate * Lookup the instance, locking only the event queue. 20347c478bd9Sstevel@tonic-gate * Can't grab ri_lock here because it might be held 20357c478bd9Sstevel@tonic-gate * by a long-running method. 20367c478bd9Sstevel@tonic-gate */ 20377c478bd9Sstevel@tonic-gate rip = inst_lookup_queue(e->rpe_inst); 20387c478bd9Sstevel@tonic-gate if (rip == NULL) { 20397c478bd9Sstevel@tonic-gate log_error(LOG_INFO, "Restarter: " 20407c478bd9Sstevel@tonic-gate "Ignoring %s command for unknown service " 20417c478bd9Sstevel@tonic-gate "%s.\n", event_names[e->rpe_type], 20427c478bd9Sstevel@tonic-gate e->rpe_inst); 20437c478bd9Sstevel@tonic-gate goto nolookup; 20447c478bd9Sstevel@tonic-gate } 20457c478bd9Sstevel@tonic-gate 20467c478bd9Sstevel@tonic-gate /* Keep ADMIN events from filling up the queue. */ 20477c478bd9Sstevel@tonic-gate if (is_admin_event(e->rpe_type) && 20487c478bd9Sstevel@tonic-gate uu_list_numnodes(rip->ri_queue) > 20497c478bd9Sstevel@tonic-gate RINST_QUEUE_THRESHOLD) { 20507c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 20517c478bd9Sstevel@tonic-gate log_instance(rip, B_TRUE, "Instance event " 20527c478bd9Sstevel@tonic-gate "queue overflow. Dropping administrative " 20537c478bd9Sstevel@tonic-gate "request."); 20547c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "%s: Instance event " 20557c478bd9Sstevel@tonic-gate "queue overflow. Dropping administrative " 20567c478bd9Sstevel@tonic-gate "request.\n", rip->ri_i.i_fmri); 20577c478bd9Sstevel@tonic-gate goto nolookup; 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate /* Now add the event to the instance queue. */ 20617c478bd9Sstevel@tonic-gate restarter_queue_event(rip, e); 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate if (rip->ri_queue_thread == 0) { 20647c478bd9Sstevel@tonic-gate /* 20657c478bd9Sstevel@tonic-gate * Start a thread if one isn't already 20667c478bd9Sstevel@tonic-gate * running. 20677c478bd9Sstevel@tonic-gate */ 20687c478bd9Sstevel@tonic-gate fmri = safe_strdup(e->rpe_inst); 20697c478bd9Sstevel@tonic-gate rip->ri_queue_thread = startd_thread_create( 20707c478bd9Sstevel@tonic-gate restarter_process_events, (void *)fmri); 20717c478bd9Sstevel@tonic-gate } else { 20727c478bd9Sstevel@tonic-gate /* 20737c478bd9Sstevel@tonic-gate * Signal the existing thread that there's 20747c478bd9Sstevel@tonic-gate * a new event. 20757c478bd9Sstevel@tonic-gate */ 20767c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast( 20777c478bd9Sstevel@tonic-gate &rip->ri_queue_cv); 20787c478bd9Sstevel@tonic-gate } 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&rip->ri_queue_lock); 20817c478bd9Sstevel@tonic-gate nolookup: 20827c478bd9Sstevel@tonic-gate restarter_event_release(e); 20837c478bd9Sstevel@tonic-gate 20847c478bd9Sstevel@tonic-gate MUTEX_LOCK(&ru->restarter_update_lock); 20857c478bd9Sstevel@tonic-gate } 20867c478bd9Sstevel@tonic-gate } 20877c478bd9Sstevel@tonic-gate 20887c478bd9Sstevel@tonic-gate /* 20897c478bd9Sstevel@tonic-gate * Unreachable for now -- there's currently no graceful cleanup 20907c478bd9Sstevel@tonic-gate * called on exit(). 20917c478bd9Sstevel@tonic-gate */ 20927c478bd9Sstevel@tonic-gate (void) scf_handle_unbind(h); 20937c478bd9Sstevel@tonic-gate scf_handle_destroy(h); 20947c478bd9Sstevel@tonic-gate return (NULL); 20957c478bd9Sstevel@tonic-gate } 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate static restarter_inst_t * 20987c478bd9Sstevel@tonic-gate contract_to_inst(ctid_t ctid) 20997c478bd9Sstevel@tonic-gate { 21007c478bd9Sstevel@tonic-gate restarter_inst_t *inst; 21017c478bd9Sstevel@tonic-gate int id; 21027c478bd9Sstevel@tonic-gate 21037c478bd9Sstevel@tonic-gate id = lookup_inst_by_contract(ctid); 21047c478bd9Sstevel@tonic-gate if (id == -1) 21057c478bd9Sstevel@tonic-gate return (NULL); 21067c478bd9Sstevel@tonic-gate 21077c478bd9Sstevel@tonic-gate inst = inst_lookup_by_id(id); 21087c478bd9Sstevel@tonic-gate if (inst != NULL) { 21097c478bd9Sstevel@tonic-gate /* 21107c478bd9Sstevel@tonic-gate * Since ri_lock isn't held by the contract id lookup, this 21117c478bd9Sstevel@tonic-gate * instance may have been restarted and now be in a new 21127c478bd9Sstevel@tonic-gate * contract, making the old contract no longer valid for this 21137c478bd9Sstevel@tonic-gate * instance. 21147c478bd9Sstevel@tonic-gate */ 21157c478bd9Sstevel@tonic-gate if (ctid != inst->ri_i.i_primary_ctid) { 21167c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 21177c478bd9Sstevel@tonic-gate inst = NULL; 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate return (inst); 21217c478bd9Sstevel@tonic-gate } 21227c478bd9Sstevel@tonic-gate 21237c478bd9Sstevel@tonic-gate /* 21247c478bd9Sstevel@tonic-gate * void contract_action() 21257c478bd9Sstevel@tonic-gate * Take action on contract events. 21267c478bd9Sstevel@tonic-gate */ 21277c478bd9Sstevel@tonic-gate static void 21287c478bd9Sstevel@tonic-gate contract_action(scf_handle_t *h, restarter_inst_t *inst, ctid_t id, 21297c478bd9Sstevel@tonic-gate uint32_t type) 21307c478bd9Sstevel@tonic-gate { 21317c478bd9Sstevel@tonic-gate const char *fmri = inst->ri_i.i_fmri; 21327c478bd9Sstevel@tonic-gate 213353f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 21347c478bd9Sstevel@tonic-gate 21357c478bd9Sstevel@tonic-gate /* 21367c478bd9Sstevel@tonic-gate * If startd has stopped this contract, there is no need to 21377c478bd9Sstevel@tonic-gate * stop it again. 21387c478bd9Sstevel@tonic-gate */ 21397c478bd9Sstevel@tonic-gate if (inst->ri_i.i_primary_ctid > 0 && 21407c478bd9Sstevel@tonic-gate inst->ri_i.i_primary_ctid_stopped) 21417c478bd9Sstevel@tonic-gate return; 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate if ((type & (CT_PR_EV_EMPTY | CT_PR_EV_CORE | CT_PR_EV_SIGNAL 21447c478bd9Sstevel@tonic-gate | CT_PR_EV_HWERR)) == 0) { 21457c478bd9Sstevel@tonic-gate /* 21467c478bd9Sstevel@tonic-gate * There shouldn't be other events, since that's not how we set 21477c478bd9Sstevel@tonic-gate * the terms. Thus, just log an error and drive on. 21487c478bd9Sstevel@tonic-gate */ 21497c478bd9Sstevel@tonic-gate log_framework(LOG_NOTICE, 21507c478bd9Sstevel@tonic-gate "%s: contract %ld received unexpected critical event " 21517c478bd9Sstevel@tonic-gate "(%d)\n", fmri, id, type); 21527c478bd9Sstevel@tonic-gate return; 21537c478bd9Sstevel@tonic-gate } 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate assert(instance_in_transition(inst) == 0); 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate if (instance_is_wait_style(inst)) { 21587c478bd9Sstevel@tonic-gate /* 21597c478bd9Sstevel@tonic-gate * We ignore all events; if they impact the 21607c478bd9Sstevel@tonic-gate * process we're monitoring, then the 21617c478bd9Sstevel@tonic-gate * wait_thread will stop the instance. 21627c478bd9Sstevel@tonic-gate */ 21637c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, 21647c478bd9Sstevel@tonic-gate "%s: ignoring contract event on wait-style service\n", 21657c478bd9Sstevel@tonic-gate fmri); 21667c478bd9Sstevel@tonic-gate } else { 21677c478bd9Sstevel@tonic-gate /* 21687c478bd9Sstevel@tonic-gate * A CT_PR_EV_EMPTY event is an RSTOP_EXIT request. 21697c478bd9Sstevel@tonic-gate */ 21707c478bd9Sstevel@tonic-gate switch (type) { 21717c478bd9Sstevel@tonic-gate case CT_PR_EV_EMPTY: 21727c478bd9Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_EXIT); 21737c478bd9Sstevel@tonic-gate break; 21747c478bd9Sstevel@tonic-gate case CT_PR_EV_CORE: 21757c478bd9Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_CORE); 21767c478bd9Sstevel@tonic-gate break; 21777c478bd9Sstevel@tonic-gate case CT_PR_EV_SIGNAL: 21787c478bd9Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_SIGNAL); 21797c478bd9Sstevel@tonic-gate break; 21807c478bd9Sstevel@tonic-gate case CT_PR_EV_HWERR: 21817c478bd9Sstevel@tonic-gate (void) stop_instance(h, inst, RSTOP_HWERR); 21827c478bd9Sstevel@tonic-gate break; 21837c478bd9Sstevel@tonic-gate } 21847c478bd9Sstevel@tonic-gate } 21857c478bd9Sstevel@tonic-gate } 21867c478bd9Sstevel@tonic-gate 21877c478bd9Sstevel@tonic-gate /* 21887c478bd9Sstevel@tonic-gate * void *restarter_contract_event_thread(void *) 21897c478bd9Sstevel@tonic-gate * Listens to the process contract bundle for critical events, taking action 21907c478bd9Sstevel@tonic-gate * on events from contracts we know we are responsible for. 21917c478bd9Sstevel@tonic-gate */ 21927c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 21937c478bd9Sstevel@tonic-gate static void * 21947c478bd9Sstevel@tonic-gate restarter_contracts_event_thread(void *unused) 21957c478bd9Sstevel@tonic-gate { 21967c478bd9Sstevel@tonic-gate int fd, err; 21977c478bd9Sstevel@tonic-gate scf_handle_t *local_handle; 21987c478bd9Sstevel@tonic-gate 21997c478bd9Sstevel@tonic-gate /* 22007c478bd9Sstevel@tonic-gate * Await graph load completion. That is, stop here, until we've scanned 22017c478bd9Sstevel@tonic-gate * the repository for contract - instance associations. 22027c478bd9Sstevel@tonic-gate */ 22037c478bd9Sstevel@tonic-gate MUTEX_LOCK(&st->st_load_lock); 22047c478bd9Sstevel@tonic-gate while (!(st->st_load_complete && st->st_load_instances == 0)) 22057c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&st->st_load_cv, &st->st_load_lock); 22067c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&st->st_load_lock); 22077c478bd9Sstevel@tonic-gate 22087c478bd9Sstevel@tonic-gate /* 22097c478bd9Sstevel@tonic-gate * This is a new thread, and thus, gets its own handle 22107c478bd9Sstevel@tonic-gate * to the repository. 22117c478bd9Sstevel@tonic-gate */ 22127c478bd9Sstevel@tonic-gate if ((local_handle = libscf_handle_create_bound(SCF_VERSION)) == NULL) 22137c478bd9Sstevel@tonic-gate uu_die("Unable to bind a new repository handle: %s\n", 22147c478bd9Sstevel@tonic-gate scf_strerror(scf_error())); 22157c478bd9Sstevel@tonic-gate 22167c478bd9Sstevel@tonic-gate fd = open64(CTFS_ROOT "/process/pbundle", O_RDONLY); 22177c478bd9Sstevel@tonic-gate if (fd == -1) 22187c478bd9Sstevel@tonic-gate uu_die("process bundle open failed"); 22197c478bd9Sstevel@tonic-gate 22207c478bd9Sstevel@tonic-gate /* 22217c478bd9Sstevel@tonic-gate * Make sure we get all events (including those generated by configd 22227c478bd9Sstevel@tonic-gate * before this thread was started). 22237c478bd9Sstevel@tonic-gate */ 22247c478bd9Sstevel@tonic-gate err = ct_event_reset(fd); 22257c478bd9Sstevel@tonic-gate assert(err == 0); 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate for (;;) { 22287c478bd9Sstevel@tonic-gate int efd, sfd; 22297c478bd9Sstevel@tonic-gate ct_evthdl_t ev; 22307c478bd9Sstevel@tonic-gate uint32_t type; 22317c478bd9Sstevel@tonic-gate ctevid_t evid; 22327c478bd9Sstevel@tonic-gate ct_stathdl_t status; 22337c478bd9Sstevel@tonic-gate ctid_t ctid; 22347c478bd9Sstevel@tonic-gate restarter_inst_t *inst; 22357c478bd9Sstevel@tonic-gate uint64_t cookie; 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate if (err = ct_event_read_critical(fd, &ev)) { 22387c478bd9Sstevel@tonic-gate log_error(LOG_WARNING, 22397c478bd9Sstevel@tonic-gate "Error reading next contract event: %s", 22407c478bd9Sstevel@tonic-gate strerror(err)); 22417c478bd9Sstevel@tonic-gate continue; 22427c478bd9Sstevel@tonic-gate } 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate evid = ct_event_get_evid(ev); 22457c478bd9Sstevel@tonic-gate ctid = ct_event_get_ctid(ev); 22467c478bd9Sstevel@tonic-gate type = ct_event_get_type(ev); 22477c478bd9Sstevel@tonic-gate 22487c478bd9Sstevel@tonic-gate /* Fetch cookie. */ 22497c478bd9Sstevel@tonic-gate if ((sfd = contract_open(ctid, "process", "status", O_RDONLY)) 22507c478bd9Sstevel@tonic-gate < 0) { 22517c478bd9Sstevel@tonic-gate ct_event_free(ev); 22527c478bd9Sstevel@tonic-gate continue; 22537c478bd9Sstevel@tonic-gate } 22547c478bd9Sstevel@tonic-gate 22557c478bd9Sstevel@tonic-gate if (err = ct_status_read(sfd, CTD_COMMON, &status)) { 22567c478bd9Sstevel@tonic-gate log_framework(LOG_WARNING, "Could not get status for " 22577c478bd9Sstevel@tonic-gate "contract %ld: %s\n", ctid, strerror(err)); 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate startd_close(sfd); 22607c478bd9Sstevel@tonic-gate ct_event_free(ev); 22617c478bd9Sstevel@tonic-gate continue; 22627c478bd9Sstevel@tonic-gate } 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate cookie = ct_status_get_cookie(status); 22657c478bd9Sstevel@tonic-gate 2266dfe57350Sjeanm log_framework(LOG_DEBUG, "Received event %d for ctid %ld " 2267dfe57350Sjeanm "cookie %lld\n", type, ctid, cookie); 2268dfe57350Sjeanm 22697c478bd9Sstevel@tonic-gate ct_status_free(status); 22707c478bd9Sstevel@tonic-gate 22717c478bd9Sstevel@tonic-gate startd_close(sfd); 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate /* 22747c478bd9Sstevel@tonic-gate * svc.configd(1M) restart handling performed by the 22757c478bd9Sstevel@tonic-gate * fork_configd_thread. We don't acknowledge, as that thread 22767c478bd9Sstevel@tonic-gate * will do so. 22777c478bd9Sstevel@tonic-gate */ 22787c478bd9Sstevel@tonic-gate if (cookie == CONFIGD_COOKIE) { 22797c478bd9Sstevel@tonic-gate ct_event_free(ev); 22807c478bd9Sstevel@tonic-gate continue; 22817c478bd9Sstevel@tonic-gate } 22827c478bd9Sstevel@tonic-gate 2283dfe57350Sjeanm inst = NULL; 2284dfe57350Sjeanm if (storing_contract != 0 && 2285dfe57350Sjeanm (inst = contract_to_inst(ctid)) == NULL) { 2286dfe57350Sjeanm /* 2287dfe57350Sjeanm * This can happen for two reasons: 2288dfe57350Sjeanm * - method_run() has not yet stored the 2289dfe57350Sjeanm * the contract into the internal hash table. 2290dfe57350Sjeanm * - we receive an EMPTY event for an abandoned 2291dfe57350Sjeanm * contract. 2292dfe57350Sjeanm * If there is any contract in the process of 2293dfe57350Sjeanm * being stored into the hash table then re-read 2294dfe57350Sjeanm * the event later. 2295dfe57350Sjeanm */ 2296dfe57350Sjeanm log_framework(LOG_DEBUG, 2297dfe57350Sjeanm "Reset event %d for unknown " 2298dfe57350Sjeanm "contract id %ld\n", type, ctid); 2299dfe57350Sjeanm 2300dfe57350Sjeanm /* don't go too fast */ 2301dfe57350Sjeanm (void) poll(NULL, 0, 100); 2302dfe57350Sjeanm 2303dfe57350Sjeanm (void) ct_event_reset(fd); 2304dfe57350Sjeanm ct_event_free(ev); 2305dfe57350Sjeanm continue; 2306dfe57350Sjeanm } 2307dfe57350Sjeanm 2308dfe57350Sjeanm /* 2309dfe57350Sjeanm * Do not call contract_to_inst() again if first 2310dfe57350Sjeanm * call succeeded. 2311dfe57350Sjeanm */ 2312dfe57350Sjeanm if (inst == NULL) 23137c478bd9Sstevel@tonic-gate inst = contract_to_inst(ctid); 23147c478bd9Sstevel@tonic-gate if (inst == NULL) { 23157c478bd9Sstevel@tonic-gate /* 23167c478bd9Sstevel@tonic-gate * This can happen if we receive an EMPTY 23177c478bd9Sstevel@tonic-gate * event for an abandoned contract. 23187c478bd9Sstevel@tonic-gate */ 23197c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, 23207c478bd9Sstevel@tonic-gate "Received event %d for unknown contract id " 23217c478bd9Sstevel@tonic-gate "%ld\n", type, ctid); 23227c478bd9Sstevel@tonic-gate } else { 23237c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, 23247c478bd9Sstevel@tonic-gate "Received event %d for contract id " 23257c478bd9Sstevel@tonic-gate "%ld (%s)\n", type, ctid, 23267c478bd9Sstevel@tonic-gate inst->ri_i.i_fmri); 23277c478bd9Sstevel@tonic-gate 23287c478bd9Sstevel@tonic-gate contract_action(local_handle, inst, ctid, type); 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&inst->ri_lock); 23317c478bd9Sstevel@tonic-gate } 23327c478bd9Sstevel@tonic-gate 23337c478bd9Sstevel@tonic-gate efd = contract_open(ct_event_get_ctid(ev), "process", "ctl", 23347c478bd9Sstevel@tonic-gate O_WRONLY); 23357c478bd9Sstevel@tonic-gate if (efd != -1) { 23367c478bd9Sstevel@tonic-gate (void) ct_ctl_ack(efd, evid); 23377c478bd9Sstevel@tonic-gate startd_close(efd); 23387c478bd9Sstevel@tonic-gate } 23397c478bd9Sstevel@tonic-gate 23407c478bd9Sstevel@tonic-gate ct_event_free(ev); 23417c478bd9Sstevel@tonic-gate 23427c478bd9Sstevel@tonic-gate } 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 23457c478bd9Sstevel@tonic-gate return (NULL); 23467c478bd9Sstevel@tonic-gate } 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate /* 23497c478bd9Sstevel@tonic-gate * Timeout queue, processed by restarter_timeouts_event_thread(). 23507c478bd9Sstevel@tonic-gate */ 23517c478bd9Sstevel@tonic-gate timeout_queue_t *timeouts; 23527c478bd9Sstevel@tonic-gate static uu_list_pool_t *timeout_pool; 23537c478bd9Sstevel@tonic-gate 23547c478bd9Sstevel@tonic-gate typedef struct timeout_update { 23557c478bd9Sstevel@tonic-gate pthread_mutex_t tu_lock; 23567c478bd9Sstevel@tonic-gate pthread_cond_t tu_cv; 23577c478bd9Sstevel@tonic-gate int tu_wakeup; 23587c478bd9Sstevel@tonic-gate } timeout_update_t; 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate timeout_update_t *tu; 23617c478bd9Sstevel@tonic-gate 23627c478bd9Sstevel@tonic-gate static const char *timeout_ovr_svcs[] = { 23637c478bd9Sstevel@tonic-gate "svc:/system/manifest-import:default", 23647c478bd9Sstevel@tonic-gate "svc:/network/initial:default", 23657c478bd9Sstevel@tonic-gate "svc:/network/service:default", 23667c478bd9Sstevel@tonic-gate "svc:/system/rmtmpfiles:default", 23677c478bd9Sstevel@tonic-gate "svc:/network/loopback:default", 23687c478bd9Sstevel@tonic-gate "svc:/network/physical:default", 23697c478bd9Sstevel@tonic-gate "svc:/system/device/local:default", 23707c478bd9Sstevel@tonic-gate "svc:/system/filesystem/usr:default", 23717c478bd9Sstevel@tonic-gate "svc:/system/filesystem/minimal:default", 23727c478bd9Sstevel@tonic-gate "svc:/system/filesystem/local:default", 23737c478bd9Sstevel@tonic-gate NULL 23747c478bd9Sstevel@tonic-gate }; 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate int 23777c478bd9Sstevel@tonic-gate is_timeout_ovr(restarter_inst_t *inst) 23787c478bd9Sstevel@tonic-gate { 23797c478bd9Sstevel@tonic-gate int i; 23807c478bd9Sstevel@tonic-gate 23817c478bd9Sstevel@tonic-gate for (i = 0; timeout_ovr_svcs[i] != NULL; ++i) { 23827c478bd9Sstevel@tonic-gate if (strcmp(inst->ri_i.i_fmri, timeout_ovr_svcs[i]) == 0) { 23837c478bd9Sstevel@tonic-gate log_instance(inst, B_TRUE, "Timeout override by " 23845ca87c7fSlianep "svc.startd. Using infinite timeout."); 23857c478bd9Sstevel@tonic-gate return (1); 23867c478bd9Sstevel@tonic-gate } 23877c478bd9Sstevel@tonic-gate } 23887c478bd9Sstevel@tonic-gate 23897c478bd9Sstevel@tonic-gate return (0); 23907c478bd9Sstevel@tonic-gate } 23917c478bd9Sstevel@tonic-gate 23927c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 23937c478bd9Sstevel@tonic-gate static int 23947c478bd9Sstevel@tonic-gate timeout_compare(const void *lc_arg, const void *rc_arg, void *private) 23957c478bd9Sstevel@tonic-gate { 23967c478bd9Sstevel@tonic-gate hrtime_t t1 = ((const timeout_entry_t *)lc_arg)->te_timeout; 23977c478bd9Sstevel@tonic-gate hrtime_t t2 = ((const timeout_entry_t *)rc_arg)->te_timeout; 23987c478bd9Sstevel@tonic-gate 23997c478bd9Sstevel@tonic-gate if (t1 > t2) 24007c478bd9Sstevel@tonic-gate return (1); 24017c478bd9Sstevel@tonic-gate else if (t1 < t2) 24027c478bd9Sstevel@tonic-gate return (-1); 24037c478bd9Sstevel@tonic-gate return (0); 24047c478bd9Sstevel@tonic-gate } 24057c478bd9Sstevel@tonic-gate 24067c478bd9Sstevel@tonic-gate void 24077c478bd9Sstevel@tonic-gate timeout_init() 24087c478bd9Sstevel@tonic-gate { 24097c478bd9Sstevel@tonic-gate timeouts = startd_zalloc(sizeof (timeout_queue_t)); 24107c478bd9Sstevel@tonic-gate 24117c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&timeouts->tq_lock, &mutex_attrs); 24127c478bd9Sstevel@tonic-gate 24137c478bd9Sstevel@tonic-gate timeout_pool = startd_list_pool_create("timeouts", 24147c478bd9Sstevel@tonic-gate sizeof (timeout_entry_t), offsetof(timeout_entry_t, te_link), 24157c478bd9Sstevel@tonic-gate timeout_compare, UU_LIST_POOL_DEBUG); 24167c478bd9Sstevel@tonic-gate assert(timeout_pool != NULL); 24177c478bd9Sstevel@tonic-gate 24187c478bd9Sstevel@tonic-gate timeouts->tq_list = startd_list_create(timeout_pool, 24197c478bd9Sstevel@tonic-gate timeouts, UU_LIST_SORTED); 24207c478bd9Sstevel@tonic-gate assert(timeouts->tq_list != NULL); 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate tu = startd_zalloc(sizeof (timeout_update_t)); 24237c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&tu->tu_cv, NULL); 24247c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&tu->tu_lock, &mutex_attrs); 24257c478bd9Sstevel@tonic-gate } 24267c478bd9Sstevel@tonic-gate 24277c478bd9Sstevel@tonic-gate void 24287c478bd9Sstevel@tonic-gate timeout_insert(restarter_inst_t *inst, ctid_t cid, uint64_t timeout_sec) 24297c478bd9Sstevel@tonic-gate { 24307c478bd9Sstevel@tonic-gate hrtime_t now, timeout; 24317c478bd9Sstevel@tonic-gate timeout_entry_t *entry; 24327c478bd9Sstevel@tonic-gate uu_list_index_t idx; 24337c478bd9Sstevel@tonic-gate 243453f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 24357c478bd9Sstevel@tonic-gate 24367c478bd9Sstevel@tonic-gate now = gethrtime(); 24377c478bd9Sstevel@tonic-gate 24387c478bd9Sstevel@tonic-gate /* 24397c478bd9Sstevel@tonic-gate * If we overflow LLONG_MAX, we're never timing out anyways, so 24407c478bd9Sstevel@tonic-gate * just return. 24417c478bd9Sstevel@tonic-gate */ 24427c478bd9Sstevel@tonic-gate if (timeout_sec >= (LLONG_MAX - now) / 1000000000LL) { 24437c478bd9Sstevel@tonic-gate log_instance(inst, B_TRUE, "timeout_seconds too large, " 24447c478bd9Sstevel@tonic-gate "treating as infinite."); 24457c478bd9Sstevel@tonic-gate return; 24467c478bd9Sstevel@tonic-gate } 24477c478bd9Sstevel@tonic-gate 24487c478bd9Sstevel@tonic-gate /* hrtime is in nanoseconds. Convert timeout_sec. */ 24497c478bd9Sstevel@tonic-gate timeout = now + (timeout_sec * 1000000000LL); 24507c478bd9Sstevel@tonic-gate 24517c478bd9Sstevel@tonic-gate entry = startd_alloc(sizeof (timeout_entry_t)); 24527c478bd9Sstevel@tonic-gate entry->te_timeout = timeout; 24537c478bd9Sstevel@tonic-gate entry->te_ctid = cid; 24547c478bd9Sstevel@tonic-gate entry->te_fmri = safe_strdup(inst->ri_i.i_fmri); 24557c478bd9Sstevel@tonic-gate entry->te_logstem = safe_strdup(inst->ri_logstem); 24567c478bd9Sstevel@tonic-gate entry->te_fired = 0; 24577c478bd9Sstevel@tonic-gate /* Insert the calculated timeout time onto the queue. */ 24587c478bd9Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 24597c478bd9Sstevel@tonic-gate (void) uu_list_find(timeouts->tq_list, entry, NULL, &idx); 24607c478bd9Sstevel@tonic-gate uu_list_node_init(entry, &entry->te_link, timeout_pool); 24617c478bd9Sstevel@tonic-gate uu_list_insert(timeouts->tq_list, entry, idx); 24627c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 24637c478bd9Sstevel@tonic-gate 24647c478bd9Sstevel@tonic-gate assert(inst->ri_timeout == NULL); 24657c478bd9Sstevel@tonic-gate inst->ri_timeout = entry; 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate MUTEX_LOCK(&tu->tu_lock); 24687c478bd9Sstevel@tonic-gate tu->tu_wakeup = 1; 24697c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&tu->tu_cv); 24707c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&tu->tu_lock); 24717c478bd9Sstevel@tonic-gate } 24727c478bd9Sstevel@tonic-gate 24737c478bd9Sstevel@tonic-gate 24747c478bd9Sstevel@tonic-gate void 24757c478bd9Sstevel@tonic-gate timeout_remove(restarter_inst_t *inst, ctid_t cid) 24767c478bd9Sstevel@tonic-gate { 247753f3aea0SRoger A. Faulkner assert(MUTEX_HELD(&inst->ri_lock)); 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate if (inst->ri_timeout == NULL) 24807c478bd9Sstevel@tonic-gate return; 24817c478bd9Sstevel@tonic-gate 24827c478bd9Sstevel@tonic-gate assert(inst->ri_timeout->te_ctid == cid); 24837c478bd9Sstevel@tonic-gate 24847c478bd9Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 24857c478bd9Sstevel@tonic-gate uu_list_remove(timeouts->tq_list, inst->ri_timeout); 24867c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 24877c478bd9Sstevel@tonic-gate 24887c478bd9Sstevel@tonic-gate free(inst->ri_timeout->te_fmri); 24897c478bd9Sstevel@tonic-gate free(inst->ri_timeout->te_logstem); 24907c478bd9Sstevel@tonic-gate startd_free(inst->ri_timeout, sizeof (timeout_entry_t)); 24917c478bd9Sstevel@tonic-gate inst->ri_timeout = NULL; 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate 24947c478bd9Sstevel@tonic-gate static int 24957c478bd9Sstevel@tonic-gate timeout_now() 24967c478bd9Sstevel@tonic-gate { 24977c478bd9Sstevel@tonic-gate timeout_entry_t *e; 24987c478bd9Sstevel@tonic-gate hrtime_t now; 24997c478bd9Sstevel@tonic-gate int ret; 25007c478bd9Sstevel@tonic-gate 25017c478bd9Sstevel@tonic-gate now = gethrtime(); 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate /* 25047c478bd9Sstevel@tonic-gate * Walk through the (sorted) timeouts list. While the timeout 25057c478bd9Sstevel@tonic-gate * at the head of the list is <= the current time, kill the 25067c478bd9Sstevel@tonic-gate * method. 25077c478bd9Sstevel@tonic-gate */ 25087c478bd9Sstevel@tonic-gate MUTEX_LOCK(&timeouts->tq_lock); 25097c478bd9Sstevel@tonic-gate 25107c478bd9Sstevel@tonic-gate for (e = uu_list_first(timeouts->tq_list); 25117c478bd9Sstevel@tonic-gate e != NULL && e->te_timeout <= now; 25127c478bd9Sstevel@tonic-gate e = uu_list_next(timeouts->tq_list, e)) { 25137c478bd9Sstevel@tonic-gate log_framework(LOG_WARNING, "%s: Method or service exit timed " 25147c478bd9Sstevel@tonic-gate "out. Killing contract %ld.\n", e->te_fmri, e->te_ctid); 25157c478bd9Sstevel@tonic-gate log_instance_fmri(e->te_fmri, e->te_logstem, B_TRUE, 25165ca87c7fSlianep "Method or service exit timed out. Killing contract %ld.", 25177c478bd9Sstevel@tonic-gate e->te_ctid); 25187c478bd9Sstevel@tonic-gate e->te_fired = 1; 25197c478bd9Sstevel@tonic-gate (void) contract_kill(e->te_ctid, SIGKILL, e->te_fmri); 25207c478bd9Sstevel@tonic-gate } 25217c478bd9Sstevel@tonic-gate 25227c478bd9Sstevel@tonic-gate if (uu_list_numnodes(timeouts->tq_list) > 0) 25237c478bd9Sstevel@tonic-gate ret = 0; 25247c478bd9Sstevel@tonic-gate else 25257c478bd9Sstevel@tonic-gate ret = -1; 25267c478bd9Sstevel@tonic-gate 25277c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&timeouts->tq_lock); 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate return (ret); 25307c478bd9Sstevel@tonic-gate } 25317c478bd9Sstevel@tonic-gate 25327c478bd9Sstevel@tonic-gate /* 25337c478bd9Sstevel@tonic-gate * void *restarter_timeouts_event_thread(void *) 25347c478bd9Sstevel@tonic-gate * Responsible for monitoring the method timeouts. This thread must 25357c478bd9Sstevel@tonic-gate * be started before any methods are called. 25367c478bd9Sstevel@tonic-gate */ 25377c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 25387c478bd9Sstevel@tonic-gate static void * 25397c478bd9Sstevel@tonic-gate restarter_timeouts_event_thread(void *unused) 25407c478bd9Sstevel@tonic-gate { 25417c478bd9Sstevel@tonic-gate /* 25427c478bd9Sstevel@tonic-gate * Timeouts are entered on a priority queue, which is processed by 25437c478bd9Sstevel@tonic-gate * this thread. As timeouts are specified in seconds, we'll do 25447c478bd9Sstevel@tonic-gate * the necessary processing every second, as long as the queue 25457c478bd9Sstevel@tonic-gate * is not empty. 25467c478bd9Sstevel@tonic-gate */ 25477c478bd9Sstevel@tonic-gate 25487c478bd9Sstevel@tonic-gate /*CONSTCOND*/ 25497c478bd9Sstevel@tonic-gate while (1) { 25507c478bd9Sstevel@tonic-gate /* 25517c478bd9Sstevel@tonic-gate * As long as the timeout list isn't empty, process it 25527c478bd9Sstevel@tonic-gate * every second. 25537c478bd9Sstevel@tonic-gate */ 25547c478bd9Sstevel@tonic-gate if (timeout_now() == 0) { 25557c478bd9Sstevel@tonic-gate (void) sleep(1); 25567c478bd9Sstevel@tonic-gate continue; 25577c478bd9Sstevel@tonic-gate } 25587c478bd9Sstevel@tonic-gate 25597c478bd9Sstevel@tonic-gate /* The list is empty, wait until we have more timeouts. */ 25607c478bd9Sstevel@tonic-gate MUTEX_LOCK(&tu->tu_lock); 25617c478bd9Sstevel@tonic-gate 25627c478bd9Sstevel@tonic-gate while (tu->tu_wakeup == 0) 25637c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&tu->tu_cv, &tu->tu_lock); 25647c478bd9Sstevel@tonic-gate 25657c478bd9Sstevel@tonic-gate tu->tu_wakeup = 0; 25667c478bd9Sstevel@tonic-gate MUTEX_UNLOCK(&tu->tu_lock); 25677c478bd9Sstevel@tonic-gate } 25687c478bd9Sstevel@tonic-gate 25697c478bd9Sstevel@tonic-gate return (NULL); 25707c478bd9Sstevel@tonic-gate } 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate void 25737c478bd9Sstevel@tonic-gate restarter_start() 25747c478bd9Sstevel@tonic-gate { 25757c478bd9Sstevel@tonic-gate (void) startd_thread_create(restarter_timeouts_event_thread, NULL); 25767c478bd9Sstevel@tonic-gate (void) startd_thread_create(restarter_event_thread, NULL); 25777c478bd9Sstevel@tonic-gate (void) startd_thread_create(restarter_contracts_event_thread, NULL); 25787c478bd9Sstevel@tonic-gate (void) startd_thread_create(wait_thread, NULL); 25797c478bd9Sstevel@tonic-gate } 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate 25827c478bd9Sstevel@tonic-gate void 25837c478bd9Sstevel@tonic-gate restarter_init() 25847c478bd9Sstevel@tonic-gate { 25857c478bd9Sstevel@tonic-gate restarter_instance_pool = startd_list_pool_create("restarter_instances", 25867c478bd9Sstevel@tonic-gate sizeof (restarter_inst_t), offsetof(restarter_inst_t, 25877c478bd9Sstevel@tonic-gate ri_link), restarter_instance_compare, UU_LIST_POOL_DEBUG); 25887c478bd9Sstevel@tonic-gate (void) memset(&instance_list, 0, sizeof (instance_list)); 25897c478bd9Sstevel@tonic-gate 25907c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&instance_list.ril_lock, &mutex_attrs); 25917c478bd9Sstevel@tonic-gate instance_list.ril_instance_list = startd_list_create( 25927c478bd9Sstevel@tonic-gate restarter_instance_pool, &instance_list, UU_LIST_SORTED); 25937c478bd9Sstevel@tonic-gate 25947c478bd9Sstevel@tonic-gate restarter_queue_pool = startd_list_pool_create( 25957c478bd9Sstevel@tonic-gate "restarter_instance_queue", sizeof (restarter_instance_qentry_t), 25967c478bd9Sstevel@tonic-gate offsetof(restarter_instance_qentry_t, riq_link), NULL, 25977c478bd9Sstevel@tonic-gate UU_LIST_POOL_DEBUG); 25987c478bd9Sstevel@tonic-gate 25997c478bd9Sstevel@tonic-gate contract_list_pool = startd_list_pool_create( 26007c478bd9Sstevel@tonic-gate "contract_list", sizeof (contract_entry_t), 26017c478bd9Sstevel@tonic-gate offsetof(contract_entry_t, ce_link), NULL, 26027c478bd9Sstevel@tonic-gate UU_LIST_POOL_DEBUG); 26037c478bd9Sstevel@tonic-gate contract_hash_init(); 26047c478bd9Sstevel@tonic-gate 26057c478bd9Sstevel@tonic-gate log_framework(LOG_DEBUG, "Initialized restarter\n"); 26067c478bd9Sstevel@tonic-gate } 2607