1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * This file contains a set of routines used to perform wait based method 31*7c478bd9Sstevel@tonic-gate * reaping. 32*7c478bd9Sstevel@tonic-gate */ 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <wait.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 36*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 37*7c478bd9Sstevel@tonic-gate #include <libcontract.h> 38*7c478bd9Sstevel@tonic-gate #include <errno.h> 39*7c478bd9Sstevel@tonic-gate #include <libintl.h> 40*7c478bd9Sstevel@tonic-gate #include <unistd.h> 41*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 42*7c478bd9Sstevel@tonic-gate #include <string.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/resource.h> 44*7c478bd9Sstevel@tonic-gate #include "inetd_impl.h" 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate /* inetd's open file limit, set in method_init() */ 47*7c478bd9Sstevel@tonic-gate #define INETD_NOFILE_LIMIT RLIM_INFINITY 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* structure used to represent an active method process */ 50*7c478bd9Sstevel@tonic-gate typedef struct { 51*7c478bd9Sstevel@tonic-gate int fd; /* fd of process's /proc psinfo file */ 52*7c478bd9Sstevel@tonic-gate /* associated contract id if known, else -1 */ 53*7c478bd9Sstevel@tonic-gate ctid_t cid; 54*7c478bd9Sstevel@tonic-gate pid_t pid; 55*7c478bd9Sstevel@tonic-gate instance_t *inst; /* pointer to associated instance */ 56*7c478bd9Sstevel@tonic-gate instance_method_t method; /* the method type running */ 57*7c478bd9Sstevel@tonic-gate uu_list_node_t link; 58*7c478bd9Sstevel@tonic-gate } method_el_t; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate static void unregister_method(method_el_t *); 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* list of currently executing method processes */ 65*7c478bd9Sstevel@tonic-gate static uu_list_pool_t *method_pool = NULL; 66*7c478bd9Sstevel@tonic-gate static uu_list_t *method_list = NULL; 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate /* 69*7c478bd9Sstevel@tonic-gate * File limit saved during initialization before modification, so that it can 70*7c478bd9Sstevel@tonic-gate * be reverted back to for inetd's exec'd methods. 71*7c478bd9Sstevel@tonic-gate */ 72*7c478bd9Sstevel@tonic-gate static struct rlimit saved_file_limit; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * Setup structures used for method termination monitoring. 76*7c478bd9Sstevel@tonic-gate * Returns -1 if an allocation failure occurred, else 0. 77*7c478bd9Sstevel@tonic-gate */ 78*7c478bd9Sstevel@tonic-gate int 79*7c478bd9Sstevel@tonic-gate method_init(void) 80*7c478bd9Sstevel@tonic-gate { 81*7c478bd9Sstevel@tonic-gate struct rlimit rl; 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate debug_msg("Entering method_init"); 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate /* 86*7c478bd9Sstevel@tonic-gate * Save aside the old file limit and impose one large enough to support 87*7c478bd9Sstevel@tonic-gate * all the /proc file handles we could have open. 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate (void) getrlimit(RLIMIT_NOFILE, &saved_file_limit); 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate rl.rlim_cur = rl.rlim_max = INETD_NOFILE_LIMIT; 93*7c478bd9Sstevel@tonic-gate if (setrlimit(RLIMIT_NOFILE, &rl) == -1) { 94*7c478bd9Sstevel@tonic-gate error_msg("Failed to set file limit: %s", strerror(errno)); 95*7c478bd9Sstevel@tonic-gate return (-1); 96*7c478bd9Sstevel@tonic-gate } 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate if ((method_pool = uu_list_pool_create("method_pool", 99*7c478bd9Sstevel@tonic-gate sizeof (method_el_t), offsetof(method_el_t, link), NULL, 100*7c478bd9Sstevel@tonic-gate UU_LIST_POOL_DEBUG)) == NULL) { 101*7c478bd9Sstevel@tonic-gate error_msg("%s: %s", gettext("Failed to create method pool"), 102*7c478bd9Sstevel@tonic-gate uu_strerror(uu_error())); 103*7c478bd9Sstevel@tonic-gate return (-1); 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate 106*7c478bd9Sstevel@tonic-gate if ((method_list = uu_list_create(method_pool, NULL, 0)) == NULL) { 107*7c478bd9Sstevel@tonic-gate error_msg("%s: %s", 108*7c478bd9Sstevel@tonic-gate gettext("Failed to create method list"), 109*7c478bd9Sstevel@tonic-gate uu_strerror(uu_error())); 110*7c478bd9Sstevel@tonic-gate /* let method_fini() clean-up */ 111*7c478bd9Sstevel@tonic-gate return (-1); 112*7c478bd9Sstevel@tonic-gate } 113*7c478bd9Sstevel@tonic-gate 114*7c478bd9Sstevel@tonic-gate return (0); 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate * Tear-down structures created in method_init(). 119*7c478bd9Sstevel@tonic-gate */ 120*7c478bd9Sstevel@tonic-gate void 121*7c478bd9Sstevel@tonic-gate method_fini(void) 122*7c478bd9Sstevel@tonic-gate { 123*7c478bd9Sstevel@tonic-gate debug_msg("Entering method_fini"); 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate if (method_list != NULL) { 126*7c478bd9Sstevel@tonic-gate method_el_t *me; 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate while ((me = uu_list_first(method_list)) != NULL) 129*7c478bd9Sstevel@tonic-gate unregister_method(me); 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate (void) uu_list_destroy(method_list); 132*7c478bd9Sstevel@tonic-gate method_list = NULL; 133*7c478bd9Sstevel@tonic-gate } 134*7c478bd9Sstevel@tonic-gate if (method_pool != NULL) { 135*7c478bd9Sstevel@tonic-gate (void) uu_list_pool_destroy(method_pool); 136*7c478bd9Sstevel@tonic-gate method_pool = NULL; 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* revert file limit */ 140*7c478bd9Sstevel@tonic-gate method_preexec(); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /* 144*7c478bd9Sstevel@tonic-gate * Revert file limit back to pre-initialization one. This shouldn't fail as 145*7c478bd9Sstevel@tonic-gate * long as its called *after* descriptor cleanup. 146*7c478bd9Sstevel@tonic-gate */ 147*7c478bd9Sstevel@tonic-gate void 148*7c478bd9Sstevel@tonic-gate method_preexec(void) 149*7c478bd9Sstevel@tonic-gate { 150*7c478bd9Sstevel@tonic-gate (void) setrlimit(RLIMIT_NOFILE, &saved_file_limit); 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* 155*7c478bd9Sstevel@tonic-gate * Callback function that handles the timeout of an instance's method. 156*7c478bd9Sstevel@tonic-gate * 'arg' points at the method_el_t representing the method. 157*7c478bd9Sstevel@tonic-gate */ 158*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 159*7c478bd9Sstevel@tonic-gate static void 160*7c478bd9Sstevel@tonic-gate method_timeout(iu_tq_t *tq, void *arg) 161*7c478bd9Sstevel@tonic-gate { 162*7c478bd9Sstevel@tonic-gate method_el_t *mp = arg; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate error_msg(gettext("The %s method of instance %s timed-out"), 165*7c478bd9Sstevel@tonic-gate methods[mp->method].name, mp->inst->fmri); 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate mp->inst->timer_id = -1; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate if (mp->method == IM_START) { 170*7c478bd9Sstevel@tonic-gate process_start_term(mp->inst); 171*7c478bd9Sstevel@tonic-gate } else { 172*7c478bd9Sstevel@tonic-gate process_non_start_term(mp->inst, IMRET_FAILURE); 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate unregister_method(mp); 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /* 179*7c478bd9Sstevel@tonic-gate * Registers the attributes of a running method passed as arguments so that 180*7c478bd9Sstevel@tonic-gate * the method's termination is noticed and any further processing of the 181*7c478bd9Sstevel@tonic-gate * associated instance is carried out. The function also sets up any 182*7c478bd9Sstevel@tonic-gate * necessary timers so we can detect hung methods. 183*7c478bd9Sstevel@tonic-gate * Returns -1 if either it failed to open the /proc psinfo file which is used 184*7c478bd9Sstevel@tonic-gate * to monitor the method process, it failed to setup a required timer or 185*7c478bd9Sstevel@tonic-gate * memory allocation failed; else 0. 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate int 188*7c478bd9Sstevel@tonic-gate register_method(instance_t *ins, pid_t pid, ctid_t cid, instance_method_t mthd) 189*7c478bd9Sstevel@tonic-gate { 190*7c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 191*7c478bd9Sstevel@tonic-gate int fd; 192*7c478bd9Sstevel@tonic-gate method_el_t *me; 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate debug_msg("Entering register_method: inst: %s, pid: %d, mthd: %s", 195*7c478bd9Sstevel@tonic-gate ins->fmri, pid, methods[mthd].name); 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate /* open /proc psinfo file of process to listen for POLLHUP events on */ 198*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "/proc/%u/psinfo", pid); 199*7c478bd9Sstevel@tonic-gate for (;;) { 200*7c478bd9Sstevel@tonic-gate if ((fd = open(path, O_RDONLY)) >= 0) { 201*7c478bd9Sstevel@tonic-gate break; 202*7c478bd9Sstevel@tonic-gate } else if (errno != EINTR) { 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * Don't output an error for ENOENT; we get this 205*7c478bd9Sstevel@tonic-gate * if a method has gone away whilst we were stopped, 206*7c478bd9Sstevel@tonic-gate * and we're now trying to re-listen for it. 207*7c478bd9Sstevel@tonic-gate */ 208*7c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 209*7c478bd9Sstevel@tonic-gate error_msg(gettext("Failed to open %s: %s"), 210*7c478bd9Sstevel@tonic-gate path, strerror(errno)); 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate return (-1); 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* add method record to in-memory list */ 217*7c478bd9Sstevel@tonic-gate if ((me = calloc(1, sizeof (method_el_t))) == NULL) { 218*7c478bd9Sstevel@tonic-gate error_msg(strerror(errno)); 219*7c478bd9Sstevel@tonic-gate (void) close(fd); 220*7c478bd9Sstevel@tonic-gate return (-1); 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate me->fd = fd; 223*7c478bd9Sstevel@tonic-gate me->inst = (instance_t *)ins; 224*7c478bd9Sstevel@tonic-gate me->method = mthd; 225*7c478bd9Sstevel@tonic-gate me->pid = pid; 226*7c478bd9Sstevel@tonic-gate me->cid = cid; 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate /* register a timeout for the method, if required */ 229*7c478bd9Sstevel@tonic-gate if (mthd != IM_START) { 230*7c478bd9Sstevel@tonic-gate method_info_t *mi = ins->config->methods[mthd]; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate if (mi->timeout > 0) { 233*7c478bd9Sstevel@tonic-gate assert(ins->timer_id == -1); 234*7c478bd9Sstevel@tonic-gate ins->timer_id = iu_schedule_timer(timer_queue, 235*7c478bd9Sstevel@tonic-gate mi->timeout, method_timeout, me); 236*7c478bd9Sstevel@tonic-gate if (ins->timer_id == -1) { 237*7c478bd9Sstevel@tonic-gate error_msg(gettext( 238*7c478bd9Sstevel@tonic-gate "Failed to schedule method timeout")); 239*7c478bd9Sstevel@tonic-gate free(me); 240*7c478bd9Sstevel@tonic-gate (void) close(fd); 241*7c478bd9Sstevel@tonic-gate return (-1); 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate } 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate /* 247*7c478bd9Sstevel@tonic-gate * Add fd of psinfo file to poll set, but pass 0 for events to 248*7c478bd9Sstevel@tonic-gate * poll for, so we should only get a POLLHUP event on the fd. 249*7c478bd9Sstevel@tonic-gate */ 250*7c478bd9Sstevel@tonic-gate if (set_pollfd(fd, 0) == -1) { 251*7c478bd9Sstevel@tonic-gate cancel_inst_timer(ins); 252*7c478bd9Sstevel@tonic-gate free(me); 253*7c478bd9Sstevel@tonic-gate (void) close(fd); 254*7c478bd9Sstevel@tonic-gate return (-1); 255*7c478bd9Sstevel@tonic-gate } 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate uu_list_node_init(me, &me->link, method_pool); 258*7c478bd9Sstevel@tonic-gate (void) uu_list_insert_after(method_list, NULL, me); 259*7c478bd9Sstevel@tonic-gate 260*7c478bd9Sstevel@tonic-gate return (0); 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate /* 264*7c478bd9Sstevel@tonic-gate * A counterpart to register_method(), this function stops the monitoring of a 265*7c478bd9Sstevel@tonic-gate * method process for its termination. 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate static void 268*7c478bd9Sstevel@tonic-gate unregister_method(method_el_t *me) 269*7c478bd9Sstevel@tonic-gate { 270*7c478bd9Sstevel@tonic-gate debug_msg("Entering unregister_method: inst: %s, pid: %d, mthd: %s", 271*7c478bd9Sstevel@tonic-gate me->inst->fmri, me->pid, methods[me->method].name); 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate /* cancel any timer associated with the method */ 274*7c478bd9Sstevel@tonic-gate if (me->inst->timer_id != -1) 275*7c478bd9Sstevel@tonic-gate cancel_inst_timer(me->inst); 276*7c478bd9Sstevel@tonic-gate 277*7c478bd9Sstevel@tonic-gate /* stop polling on the psinfo file fd */ 278*7c478bd9Sstevel@tonic-gate clear_pollfd(me->fd); 279*7c478bd9Sstevel@tonic-gate (void) close(me->fd); 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate /* remove method record from list */ 282*7c478bd9Sstevel@tonic-gate uu_list_remove(method_list, me); 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate free(me); 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate /* 288*7c478bd9Sstevel@tonic-gate * Unregister all methods associated with instance 'inst'. 289*7c478bd9Sstevel@tonic-gate */ 290*7c478bd9Sstevel@tonic-gate void 291*7c478bd9Sstevel@tonic-gate unregister_instance_methods(const instance_t *inst) 292*7c478bd9Sstevel@tonic-gate { 293*7c478bd9Sstevel@tonic-gate method_el_t *me = uu_list_first(method_list); 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate while (me != NULL) { 296*7c478bd9Sstevel@tonic-gate if (me->inst == inst) { 297*7c478bd9Sstevel@tonic-gate method_el_t *tmp = me; 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 300*7c478bd9Sstevel@tonic-gate unregister_method(tmp); 301*7c478bd9Sstevel@tonic-gate } else { 302*7c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 303*7c478bd9Sstevel@tonic-gate } 304*7c478bd9Sstevel@tonic-gate } 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate /* 308*7c478bd9Sstevel@tonic-gate * Process any terminated methods. For each method determined to have 309*7c478bd9Sstevel@tonic-gate * terminated, the function determines its return value and calls the 310*7c478bd9Sstevel@tonic-gate * appropriate handling function, depending on the type of the method. 311*7c478bd9Sstevel@tonic-gate */ 312*7c478bd9Sstevel@tonic-gate void 313*7c478bd9Sstevel@tonic-gate process_terminated_methods(void) 314*7c478bd9Sstevel@tonic-gate { 315*7c478bd9Sstevel@tonic-gate method_el_t *me = uu_list_first(method_list); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate debug_msg("Entering process_terminated_methods"); 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate while (me != NULL) { 320*7c478bd9Sstevel@tonic-gate struct pollfd *pfd; 321*7c478bd9Sstevel@tonic-gate pid_t pid; 322*7c478bd9Sstevel@tonic-gate int status; 323*7c478bd9Sstevel@tonic-gate int ret; 324*7c478bd9Sstevel@tonic-gate method_el_t *tmp; 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate pfd = find_pollfd(me->fd); 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate /* 329*7c478bd9Sstevel@tonic-gate * We expect to get a POLLHUP back on the fd of the process's 330*7c478bd9Sstevel@tonic-gate * open psinfo file from /proc when the method terminates. 331*7c478bd9Sstevel@tonic-gate * A POLLERR could(?) mask a POLLHUP, so handle this 332*7c478bd9Sstevel@tonic-gate * also. 333*7c478bd9Sstevel@tonic-gate */ 334*7c478bd9Sstevel@tonic-gate if ((pfd->revents & (POLLHUP|POLLERR)) == 0) { 335*7c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 336*7c478bd9Sstevel@tonic-gate continue; 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate /* get the method's exit code (no need to loop for EINTR) */ 340*7c478bd9Sstevel@tonic-gate pid = waitpid(me->pid, &status, WNOHANG); 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate switch (pid) { 343*7c478bd9Sstevel@tonic-gate case 0: /* child still around */ 344*7c478bd9Sstevel@tonic-gate /* 345*7c478bd9Sstevel@tonic-gate * Either poll() is sending us invalid POLLHUP events 346*7c478bd9Sstevel@tonic-gate * or is flagging a POLLERR on the fd. Neither should 347*7c478bd9Sstevel@tonic-gate * happen, but in the event they do, ignore this fd 348*7c478bd9Sstevel@tonic-gate * this time around and wait out the termination 349*7c478bd9Sstevel@tonic-gate * of its associated method. This may result in 350*7c478bd9Sstevel@tonic-gate * inetd swiftly looping in event_loop(), but means 351*7c478bd9Sstevel@tonic-gate * we don't miss the termination of a method. 352*7c478bd9Sstevel@tonic-gate */ 353*7c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 354*7c478bd9Sstevel@tonic-gate continue; 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate case -1: /* non-existent child */ 357*7c478bd9Sstevel@tonic-gate assert(errno == ECHILD); 358*7c478bd9Sstevel@tonic-gate /* 359*7c478bd9Sstevel@tonic-gate * the method must not be owned by inetd due to it 360*7c478bd9Sstevel@tonic-gate * persisting over an inetd restart. Let's assume the 361*7c478bd9Sstevel@tonic-gate * best, that it was successful. 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate ret = IMRET_SUCCESS; 364*7c478bd9Sstevel@tonic-gate break; 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate default: /* child terminated */ 367*7c478bd9Sstevel@tonic-gate if (WIFEXITED(status)) { 368*7c478bd9Sstevel@tonic-gate ret = WEXITSTATUS(status); 369*7c478bd9Sstevel@tonic-gate debug_msg("process %d of instance %s returned " 370*7c478bd9Sstevel@tonic-gate "%d", pid, me->inst->fmri, ret); 371*7c478bd9Sstevel@tonic-gate } else if (WIFSIGNALED(status)) { 372*7c478bd9Sstevel@tonic-gate /* 373*7c478bd9Sstevel@tonic-gate * Terminated by signal. This may be due 374*7c478bd9Sstevel@tonic-gate * to a kill that we sent from a disable or 375*7c478bd9Sstevel@tonic-gate * offline event. We flag it as a failure, but 376*7c478bd9Sstevel@tonic-gate * this flagged failure will only be processed 377*7c478bd9Sstevel@tonic-gate * in the case of non-start methods, or when 378*7c478bd9Sstevel@tonic-gate * the instance is still enabled. 379*7c478bd9Sstevel@tonic-gate */ 380*7c478bd9Sstevel@tonic-gate debug_msg("process %d of instance %s exited " 381*7c478bd9Sstevel@tonic-gate "due to signal %d", pid, me->inst->fmri, 382*7c478bd9Sstevel@tonic-gate WTERMSIG(status)); 383*7c478bd9Sstevel@tonic-gate ret = IMRET_FAILURE; 384*7c478bd9Sstevel@tonic-gate } else { 385*7c478bd9Sstevel@tonic-gate /* 386*7c478bd9Sstevel@tonic-gate * Can we actually get here? Don't think so. 387*7c478bd9Sstevel@tonic-gate * Treat it as a failure, anyway. 388*7c478bd9Sstevel@tonic-gate */ 389*7c478bd9Sstevel@tonic-gate debug_msg("waitpid() for %s method of " 390*7c478bd9Sstevel@tonic-gate "instance %s returned %d", 391*7c478bd9Sstevel@tonic-gate methods[me->method].name, me->inst->fmri, 392*7c478bd9Sstevel@tonic-gate status); 393*7c478bd9Sstevel@tonic-gate ret = IMRET_FAILURE; 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate remove_method_ids(me->inst, me->pid, me->cid, me->method); 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate /* continue state transition processing of the instance */ 400*7c478bd9Sstevel@tonic-gate if (me->method != IM_START) { 401*7c478bd9Sstevel@tonic-gate process_non_start_term(me->inst, ret); 402*7c478bd9Sstevel@tonic-gate } else { 403*7c478bd9Sstevel@tonic-gate process_start_term(me->inst); 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate if (me->cid != -1) 407*7c478bd9Sstevel@tonic-gate (void) abandon_contract(me->cid); 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate tmp = me; 410*7c478bd9Sstevel@tonic-gate me = uu_list_next(method_list, me); 411*7c478bd9Sstevel@tonic-gate unregister_method(tmp); 412*7c478bd9Sstevel@tonic-gate } 413*7c478bd9Sstevel@tonic-gate } 414