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 5*eed64e98Sgm209912 * Common Development and Distribution License (the "License"). 6*eed64e98Sgm209912 * 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 */ 217c478bd9Sstevel@tonic-gate /* 22*eed64e98Sgm209912 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * This file contains a set of routines used to perform wait based method 307c478bd9Sstevel@tonic-gate * reaping. 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <wait.h> 347c478bd9Sstevel@tonic-gate #include <sys/param.h> 357c478bd9Sstevel@tonic-gate #include <fcntl.h> 367c478bd9Sstevel@tonic-gate #include <libcontract.h> 377c478bd9Sstevel@tonic-gate #include <errno.h> 387c478bd9Sstevel@tonic-gate #include <libintl.h> 397c478bd9Sstevel@tonic-gate #include <unistd.h> 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <string.h> 427c478bd9Sstevel@tonic-gate #include <sys/resource.h> 437c478bd9Sstevel@tonic-gate #include "inetd_impl.h" 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* inetd's open file limit, set in method_init() */ 467c478bd9Sstevel@tonic-gate #define INETD_NOFILE_LIMIT RLIM_INFINITY 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* structure used to represent an active method process */ 497c478bd9Sstevel@tonic-gate typedef struct { 507c478bd9Sstevel@tonic-gate int fd; /* fd of process's /proc psinfo file */ 517c478bd9Sstevel@tonic-gate /* associated contract id if known, else -1 */ 527c478bd9Sstevel@tonic-gate ctid_t cid; 537c478bd9Sstevel@tonic-gate pid_t pid; 547c478bd9Sstevel@tonic-gate instance_t *inst; /* pointer to associated instance */ 557c478bd9Sstevel@tonic-gate instance_method_t method; /* the method type running */ 567c478bd9Sstevel@tonic-gate uu_list_node_t link; 577c478bd9Sstevel@tonic-gate } method_el_t; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate static void unregister_method(method_el_t *); 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /* list of currently executing method processes */ 647c478bd9Sstevel@tonic-gate static uu_list_pool_t *method_pool = NULL; 657c478bd9Sstevel@tonic-gate static uu_list_t *method_list = NULL; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * File limit saved during initialization before modification, so that it can 697c478bd9Sstevel@tonic-gate * be reverted back to for inetd's exec'd methods. 707c478bd9Sstevel@tonic-gate */ 717c478bd9Sstevel@tonic-gate static struct rlimit saved_file_limit; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * Setup structures used for method termination monitoring. 757c478bd9Sstevel@tonic-gate * Returns -1 if an allocation failure occurred, else 0. 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate int 787c478bd9Sstevel@tonic-gate method_init(void) 797c478bd9Sstevel@tonic-gate { 807c478bd9Sstevel@tonic-gate struct rlimit rl; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * Save aside the old file limit and impose one large enough to support 847c478bd9Sstevel@tonic-gate * all the /proc file handles we could have open. 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate (void) getrlimit(RLIMIT_NOFILE, &saved_file_limit); 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate rl.rlim_cur = rl.rlim_max = INETD_NOFILE_LIMIT; 907c478bd9Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 917c478bd9Sstevel@tonic-gate error_msg("Failed to set file limit: %s", strerror(errno)); 927c478bd9Sstevel@tonic-gate return (-1); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate if ((method_pool = uu_list_pool_create("method_pool", 967c478bd9Sstevel@tonic-gate sizeof (method_el_t), offsetof(method_el_t, link), NULL, 977c478bd9Sstevel@tonic-gate UU_LIST_POOL_DEBUG)) == NULL) { 987c478bd9Sstevel@tonic-gate error_msg("%s: %s", gettext("Failed to create method pool"), 997c478bd9Sstevel@tonic-gate uu_strerror(uu_error())); 1007c478bd9Sstevel@tonic-gate return (-1); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate if ((method_list = uu_list_create(method_pool, NULL, 0)) == NULL) { 1047c478bd9Sstevel@tonic-gate error_msg("%s: %s", 1057c478bd9Sstevel@tonic-gate gettext("Failed to create method list"), 1067c478bd9Sstevel@tonic-gate uu_strerror(uu_error())); 1077c478bd9Sstevel@tonic-gate /* let method_fini() clean-up */ 1087c478bd9Sstevel@tonic-gate return (-1); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate return (0); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * Tear-down structures created in method_init(). 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate void 1187c478bd9Sstevel@tonic-gate method_fini(void) 1197c478bd9Sstevel@tonic-gate { 1207c478bd9Sstevel@tonic-gate if (method_list != NULL) { 1217c478bd9Sstevel@tonic-gate method_el_t *me; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate while ((me = uu_list_first(method_list)) != NULL) 1247c478bd9Sstevel@tonic-gate unregister_method(me); 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate (void) uu_list_destroy(method_list); 1277c478bd9Sstevel@tonic-gate method_list = NULL; 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate if (method_pool != NULL) { 1307c478bd9Sstevel@tonic-gate (void) uu_list_pool_destroy(method_pool); 1317c478bd9Sstevel@tonic-gate method_pool = NULL; 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* revert file limit */ 1357c478bd9Sstevel@tonic-gate method_preexec(); 1367c478bd9Sstevel@tonic-gate } 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate /* 1397c478bd9Sstevel@tonic-gate * Revert file limit back to pre-initialization one. This shouldn't fail as 1407c478bd9Sstevel@tonic-gate * long as its called *after* descriptor cleanup. 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate void 1437c478bd9Sstevel@tonic-gate method_preexec(void) 1447c478bd9Sstevel@tonic-gate { 1457c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &saved_file_limit); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate /* 1507c478bd9Sstevel@tonic-gate * Callback function that handles the timeout of an instance's method. 1517c478bd9Sstevel@tonic-gate * 'arg' points at the method_el_t representing the method. 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 1547c478bd9Sstevel@tonic-gate static void 1557c478bd9Sstevel@tonic-gate method_timeout(iu_tq_t *tq, void *arg) 1567c478bd9Sstevel@tonic-gate { 1577c478bd9Sstevel@tonic-gate method_el_t *mp = arg; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate error_msg(gettext("The %s method of instance %s timed-out"), 1607c478bd9Sstevel@tonic-gate methods[mp->method].name, mp->inst->fmri); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate mp->inst->timer_id = -1; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate if (mp->method == IM_START) { 1657c478bd9Sstevel@tonic-gate process_start_term(mp->inst); 1667c478bd9Sstevel@tonic-gate } else { 1677c478bd9Sstevel@tonic-gate process_non_start_term(mp->inst, IMRET_FAILURE); 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate unregister_method(mp); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * Registers the attributes of a running method passed as arguments so that 1757c478bd9Sstevel@tonic-gate * the method's termination is noticed and any further processing of the 1767c478bd9Sstevel@tonic-gate * associated instance is carried out. The function also sets up any 1777c478bd9Sstevel@tonic-gate * necessary timers so we can detect hung methods. 1787c478bd9Sstevel@tonic-gate * Returns -1 if either it failed to open the /proc psinfo file which is used 1797c478bd9Sstevel@tonic-gate * to monitor the method process, it failed to setup a required timer or 1807c478bd9Sstevel@tonic-gate * memory allocation failed; else 0. 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate int 1837c478bd9Sstevel@tonic-gate register_method(instance_t *ins, pid_t pid, ctid_t cid, instance_method_t mthd) 1847c478bd9Sstevel@tonic-gate { 1857c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 1867c478bd9Sstevel@tonic-gate int fd; 1877c478bd9Sstevel@tonic-gate method_el_t *me; 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* open /proc psinfo file of process to listen for POLLHUP events on */ 1907c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "/proc/%u/psinfo", pid); 1917c478bd9Sstevel@tonic-gate for (;;) { 1927c478bd9Sstevel@tonic-gate if ((fd = open(path, O_RDONLY)) >= 0) { 1937c478bd9Sstevel@tonic-gate break; 1947c478bd9Sstevel@tonic-gate } else if (errno != EINTR) { 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * Don't output an error for ENOENT; we get this 1977c478bd9Sstevel@tonic-gate * if a method has gone away whilst we were stopped, 1987c478bd9Sstevel@tonic-gate * and we're now trying to re-listen for it. 1997c478bd9Sstevel@tonic-gate */ 2007c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 2017c478bd9Sstevel@tonic-gate error_msg(gettext("Failed to open %s: %s"), 2027c478bd9Sstevel@tonic-gate path, strerror(errno)); 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate return (-1); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate /* add method record to in-memory list */ 2097c478bd9Sstevel@tonic-gate if ((me = calloc(1, sizeof (method_el_t))) == NULL) { 2107c478bd9Sstevel@tonic-gate error_msg(strerror(errno)); 2117c478bd9Sstevel@tonic-gate (void) close(fd); 2127c478bd9Sstevel@tonic-gate return (-1); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate me->fd = fd; 2157c478bd9Sstevel@tonic-gate me->inst = (instance_t *)ins; 2167c478bd9Sstevel@tonic-gate me->method = mthd; 2177c478bd9Sstevel@tonic-gate me->pid = pid; 2187c478bd9Sstevel@tonic-gate me->cid = cid; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate /* register a timeout for the method, if required */ 2217c478bd9Sstevel@tonic-gate if (mthd != IM_START) { 2227c478bd9Sstevel@tonic-gate method_info_t *mi = ins->config->methods[mthd]; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate if (mi->timeout > 0) { 2257c478bd9Sstevel@tonic-gate assert(ins->timer_id == -1); 2267c478bd9Sstevel@tonic-gate ins->timer_id = iu_schedule_timer(timer_queue, 2277c478bd9Sstevel@tonic-gate mi->timeout, method_timeout, me); 2287c478bd9Sstevel@tonic-gate if (ins->timer_id == -1) { 2297c478bd9Sstevel@tonic-gate error_msg(gettext( 2307c478bd9Sstevel@tonic-gate "Failed to schedule method timeout")); 2317c478bd9Sstevel@tonic-gate free(me); 2327c478bd9Sstevel@tonic-gate (void) close(fd); 2337c478bd9Sstevel@tonic-gate return (-1); 2347c478bd9Sstevel@tonic-gate } 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* 2397c478bd9Sstevel@tonic-gate * Add fd of psinfo file to poll set, but pass 0 for events to 2407c478bd9Sstevel@tonic-gate * poll for, so we should only get a POLLHUP event on the fd. 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate if (set_pollfd(fd, 0) == -1) { 2437c478bd9Sstevel@tonic-gate cancel_inst_timer(ins); 2447c478bd9Sstevel@tonic-gate free(me); 2457c478bd9Sstevel@tonic-gate (void) close(fd); 2467c478bd9Sstevel@tonic-gate return (-1); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate uu_list_node_init(me, &me->link, method_pool); 2507c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(method_list, NULL, me); 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate return (0); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * A counterpart to register_method(), this function stops the monitoring of a 2577c478bd9Sstevel@tonic-gate * method process for its termination. 2587c478bd9Sstevel@tonic-gate */ 2597c478bd9Sstevel@tonic-gate static void 2607c478bd9Sstevel@tonic-gate unregister_method(method_el_t *me) 2617c478bd9Sstevel@tonic-gate { 2627c478bd9Sstevel@tonic-gate /* cancel any timer associated with the method */ 2637c478bd9Sstevel@tonic-gate if (me->inst->timer_id != -1) 2647c478bd9Sstevel@tonic-gate cancel_inst_timer(me->inst); 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate /* stop polling on the psinfo file fd */ 2677c478bd9Sstevel@tonic-gate clear_pollfd(me->fd); 2687c478bd9Sstevel@tonic-gate (void) close(me->fd); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate /* remove method record from list */ 2717c478bd9Sstevel@tonic-gate uu_list_remove(method_list, me); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate free(me); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate /* 2777c478bd9Sstevel@tonic-gate * Unregister all methods associated with instance 'inst'. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate void 2807c478bd9Sstevel@tonic-gate unregister_instance_methods(const instance_t *inst) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate method_el_t *me = uu_list_first(method_list); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate while (me != NULL) { 2857c478bd9Sstevel@tonic-gate if (me->inst == inst) { 2867c478bd9Sstevel@tonic-gate method_el_t *tmp = me; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 2897c478bd9Sstevel@tonic-gate unregister_method(tmp); 2907c478bd9Sstevel@tonic-gate } else { 2917c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Process any terminated methods. For each method determined to have 2987c478bd9Sstevel@tonic-gate * terminated, the function determines its return value and calls the 2997c478bd9Sstevel@tonic-gate * appropriate handling function, depending on the type of the method. 3007c478bd9Sstevel@tonic-gate */ 3017c478bd9Sstevel@tonic-gate void 3027c478bd9Sstevel@tonic-gate process_terminated_methods(void) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate method_el_t *me = uu_list_first(method_list); 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate while (me != NULL) { 3077c478bd9Sstevel@tonic-gate struct pollfd *pfd; 3087c478bd9Sstevel@tonic-gate pid_t pid; 3097c478bd9Sstevel@tonic-gate int status; 3107c478bd9Sstevel@tonic-gate int ret; 3117c478bd9Sstevel@tonic-gate method_el_t *tmp; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate pfd = find_pollfd(me->fd); 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * We expect to get a POLLHUP back on the fd of the process's 3177c478bd9Sstevel@tonic-gate * open psinfo file from /proc when the method terminates. 3187c478bd9Sstevel@tonic-gate * A POLLERR could(?) mask a POLLHUP, so handle this 3197c478bd9Sstevel@tonic-gate * also. 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate if ((pfd->revents & (POLLHUP|POLLERR)) == 0) { 3227c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 3237c478bd9Sstevel@tonic-gate continue; 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* get the method's exit code (no need to loop for EINTR) */ 3277c478bd9Sstevel@tonic-gate pid = waitpid(me->pid, &status, WNOHANG); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate switch (pid) { 3307c478bd9Sstevel@tonic-gate case 0: /* child still around */ 3317c478bd9Sstevel@tonic-gate /* 3327c478bd9Sstevel@tonic-gate * Either poll() is sending us invalid POLLHUP events 3337c478bd9Sstevel@tonic-gate * or is flagging a POLLERR on the fd. Neither should 3347c478bd9Sstevel@tonic-gate * happen, but in the event they do, ignore this fd 3357c478bd9Sstevel@tonic-gate * this time around and wait out the termination 3367c478bd9Sstevel@tonic-gate * of its associated method. This may result in 3377c478bd9Sstevel@tonic-gate * inetd swiftly looping in event_loop(), but means 3387c478bd9Sstevel@tonic-gate * we don't miss the termination of a method. 3397c478bd9Sstevel@tonic-gate */ 3407c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 3417c478bd9Sstevel@tonic-gate continue; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate case -1: /* non-existent child */ 3447c478bd9Sstevel@tonic-gate assert(errno == ECHILD); 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * the method must not be owned by inetd due to it 3477c478bd9Sstevel@tonic-gate * persisting over an inetd restart. Let's assume the 3487c478bd9Sstevel@tonic-gate * best, that it was successful. 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate ret = IMRET_SUCCESS; 3517c478bd9Sstevel@tonic-gate break; 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate default: /* child terminated */ 3547c478bd9Sstevel@tonic-gate if (WIFEXITED(status)) { 3557c478bd9Sstevel@tonic-gate ret = WEXITSTATUS(status); 3567c478bd9Sstevel@tonic-gate debug_msg("process %d of instance %s returned " 3577c478bd9Sstevel@tonic-gate "%d", pid, me->inst->fmri, ret); 3587c478bd9Sstevel@tonic-gate } else if (WIFSIGNALED(status)) { 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * Terminated by signal. This may be due 3617c478bd9Sstevel@tonic-gate * to a kill that we sent from a disable or 3627c478bd9Sstevel@tonic-gate * offline event. We flag it as a failure, but 3637c478bd9Sstevel@tonic-gate * this flagged failure will only be processed 3647c478bd9Sstevel@tonic-gate * in the case of non-start methods, or when 3657c478bd9Sstevel@tonic-gate * the instance is still enabled. 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate debug_msg("process %d of instance %s exited " 3687c478bd9Sstevel@tonic-gate "due to signal %d", pid, me->inst->fmri, 3697c478bd9Sstevel@tonic-gate WTERMSIG(status)); 3707c478bd9Sstevel@tonic-gate ret = IMRET_FAILURE; 3717c478bd9Sstevel@tonic-gate } else { 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * Can we actually get here? Don't think so. 3747c478bd9Sstevel@tonic-gate * Treat it as a failure, anyway. 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate debug_msg("waitpid() for %s method of " 3777c478bd9Sstevel@tonic-gate "instance %s returned %d", 3787c478bd9Sstevel@tonic-gate methods[me->method].name, me->inst->fmri, 3797c478bd9Sstevel@tonic-gate status); 3807c478bd9Sstevel@tonic-gate ret = IMRET_FAILURE; 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate remove_method_ids(me->inst, me->pid, me->cid, me->method); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* continue state transition processing of the instance */ 3877c478bd9Sstevel@tonic-gate if (me->method != IM_START) { 3887c478bd9Sstevel@tonic-gate process_non_start_term(me->inst, ret); 3897c478bd9Sstevel@tonic-gate } else { 3907c478bd9Sstevel@tonic-gate process_start_term(me->inst); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate if (me->cid != -1) 3947c478bd9Sstevel@tonic-gate (void) abandon_contract(me->cid); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate tmp = me; 3977c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 3987c478bd9Sstevel@tonic-gate unregister_method(tmp); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate } 401