xref: /titanic_50/usr/src/cmd/cmd-inet/sbin/dhcpagent/script_handler.c (revision 3644994cfca6e375a92aac121dbf0900522e21d1)
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
5d04ccbb3Scarlsonj  * Common Development and Distribution License (the "License").
6d04ccbb3Scarlsonj  * 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*3644994cSmeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <time.h>
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <assert.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/wait.h>
347c478bd9Sstevel@tonic-gate #include <signal.h>
357c478bd9Sstevel@tonic-gate #include <fcntl.h>
367c478bd9Sstevel@tonic-gate #include <dhcpmsg.h>
37d04ccbb3Scarlsonj 
38d04ccbb3Scarlsonj #include "agent.h"
397c478bd9Sstevel@tonic-gate #include "script_handler.h"
40d04ccbb3Scarlsonj #include "states.h"
41d04ccbb3Scarlsonj #include "interface.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * scripts are directly managed by a script helper process. dhcpagent creates
457c478bd9Sstevel@tonic-gate  * the helper process and it, in turn, creates a process to run the script
467c478bd9Sstevel@tonic-gate  * dhcpagent owns one end of a pipe and the helper process owns the other end
477c478bd9Sstevel@tonic-gate  * the helper process calls waitpid to wait for the script to exit. an alarm
487c478bd9Sstevel@tonic-gate  * is set for SCRIPT_TIMEOUT seconds. If the alarm fires, SIGTERM is sent to
497c478bd9Sstevel@tonic-gate  * the script process and a second alarm is set for SCRIPT_TIMEOUT_GRACE. if
507c478bd9Sstevel@tonic-gate  * the second alarm fires, SIGKILL is sent to forcefully kill the script. when
517c478bd9Sstevel@tonic-gate  * script exits, the helper process notifies dhcpagent by closing its end
527c478bd9Sstevel@tonic-gate  * of the pipe.
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate unsigned int	script_count;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * the signal to send to the script process. it is a global variable
597c478bd9Sstevel@tonic-gate  * to this file as sigterm_handler needs it.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static int	script_signal = SIGTERM;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * script's absolute timeout value. the first timeout is set to SCRIPT_TIMEOUT
667c478bd9Sstevel@tonic-gate  * seconds from the time it is started. SIGTERM is sent on the first timeout
677c478bd9Sstevel@tonic-gate  * the second timeout is set to SCRIPT_TIMEOUT_GRACE from the first timeout
687c478bd9Sstevel@tonic-gate  * and SIGKILL is sent on the second timeout.
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate static time_t	timeout;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate /*
73*3644994cSmeem  * sigalarm_handler(): signal handler for SIGALRM
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  *   input: int: signal the handler was called with
767c478bd9Sstevel@tonic-gate  *  output: void
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /* ARGSUSED */
807c478bd9Sstevel@tonic-gate static void
sigalarm_handler(int sig)817c478bd9Sstevel@tonic-gate sigalarm_handler(int sig)
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate 	time_t	now;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	/* set a another alarm if it fires too early */
867c478bd9Sstevel@tonic-gate 	now = time(NULL);
877c478bd9Sstevel@tonic-gate 	if (now < timeout)
887c478bd9Sstevel@tonic-gate 		(void) alarm(timeout - now);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate  * sigterm_handler(): signal handler for SIGTERM, fired when dhcpagent wants
937c478bd9Sstevel@tonic-gate  *		      to stop the script
947c478bd9Sstevel@tonic-gate  *   input: int: signal the handler was called with
957c478bd9Sstevel@tonic-gate  *  output: void
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* ARGSUSED */
997c478bd9Sstevel@tonic-gate static void
sigterm_handler(int sig)1007c478bd9Sstevel@tonic-gate sigterm_handler(int sig)
1017c478bd9Sstevel@tonic-gate {
1027c478bd9Sstevel@tonic-gate 	if (script_signal != SIGKILL) {
1037c478bd9Sstevel@tonic-gate 		/* send SIGKILL SCRIPT_TIMEOUT_GRACE seconds from now */
1047c478bd9Sstevel@tonic-gate 		script_signal = SIGKILL;
1057c478bd9Sstevel@tonic-gate 		timeout = time(NULL) + SCRIPT_TIMEOUT_GRACE;
1067c478bd9Sstevel@tonic-gate 		(void) alarm(SCRIPT_TIMEOUT_GRACE);
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate  * run_script(): it forks a process to execute the script
1127c478bd9Sstevel@tonic-gate  *
113d04ccbb3Scarlsonj  *   input: dhcp_smach_t *: the state machine
1147c478bd9Sstevel@tonic-gate  *	    const char *: the event name
1157c478bd9Sstevel@tonic-gate  *	    int: the pipe end owned by the script helper process
1167c478bd9Sstevel@tonic-gate  *  output: void
1177c478bd9Sstevel@tonic-gate  */
118d04ccbb3Scarlsonj 
1197c478bd9Sstevel@tonic-gate static void
run_script(dhcp_smach_t * dsmp,const char * event,int fd)120d04ccbb3Scarlsonj run_script(dhcp_smach_t *dsmp, const char *event, int fd)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	int		n;
1237c478bd9Sstevel@tonic-gate 	char		c;
124d04ccbb3Scarlsonj 	char		*path;
1257c478bd9Sstevel@tonic-gate 	char		*name;
1267c478bd9Sstevel@tonic-gate 	pid_t		pid;
1277c478bd9Sstevel@tonic-gate 	time_t		now;
1287c478bd9Sstevel@tonic-gate 
129*3644994cSmeem 	if ((pid = fork()) == -1)
1307c478bd9Sstevel@tonic-gate 		return;
131*3644994cSmeem 
1327c478bd9Sstevel@tonic-gate 	if (pid == 0) {
133d04ccbb3Scarlsonj 		path = SCRIPT_PATH;
134d04ccbb3Scarlsonj 		name = strrchr(path, '/') + 1;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 		/* close all files */
1377c478bd9Sstevel@tonic-gate 		closefrom(0);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 		/* redirect stdin, stdout and stderr to /dev/null */
1407c478bd9Sstevel@tonic-gate 		if ((n = open("/dev/null", O_RDWR)) < 0)
141d04ccbb3Scarlsonj 			_exit(127);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 		(void) dup2(n, STDOUT_FILENO);
1447c478bd9Sstevel@tonic-gate 		(void) dup2(n, STDERR_FILENO);
145d04ccbb3Scarlsonj 		(void) execl(path, name, dsmp->dsm_name, event, NULL);
1467c478bd9Sstevel@tonic-gate 		_exit(127);
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	/*
1507c478bd9Sstevel@tonic-gate 	 * the first timeout fires SCRIPT_TIMEOUT seconds from now.
1517c478bd9Sstevel@tonic-gate 	 */
1527c478bd9Sstevel@tonic-gate 	timeout = time(NULL) + SCRIPT_TIMEOUT;
1537c478bd9Sstevel@tonic-gate 	(void) sigset(SIGALRM, sigalarm_handler);
1547c478bd9Sstevel@tonic-gate 	(void) alarm(SCRIPT_TIMEOUT);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	/*
1577c478bd9Sstevel@tonic-gate 	 * pass script's pid to dhcpagent.
1587c478bd9Sstevel@tonic-gate 	 */
1597c478bd9Sstevel@tonic-gate 	(void) write(fd, &pid, sizeof (pid));
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	for (;;) {
1627c478bd9Sstevel@tonic-gate 		if (waitpid(pid, NULL, 0) >= 0) {
1637c478bd9Sstevel@tonic-gate 			/* script has exited */
1647c478bd9Sstevel@tonic-gate 			c = SCRIPT_OK;
1657c478bd9Sstevel@tonic-gate 			break;
1667c478bd9Sstevel@tonic-gate 		}
1677c478bd9Sstevel@tonic-gate 
168*3644994cSmeem 		if (errno != EINTR)
1697c478bd9Sstevel@tonic-gate 			return;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		now = time(NULL);
1727c478bd9Sstevel@tonic-gate 		if (now >= timeout) {
1737c478bd9Sstevel@tonic-gate 			(void) kill(pid, script_signal);
1747c478bd9Sstevel@tonic-gate 			if (script_signal == SIGKILL) {
1757c478bd9Sstevel@tonic-gate 				c = SCRIPT_KILLED;
1767c478bd9Sstevel@tonic-gate 				break;
1777c478bd9Sstevel@tonic-gate 			}
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 			script_signal = SIGKILL;
1807c478bd9Sstevel@tonic-gate 			timeout = now + SCRIPT_TIMEOUT_GRACE;
1817c478bd9Sstevel@tonic-gate 			(void) alarm(SCRIPT_TIMEOUT_GRACE);
1827c478bd9Sstevel@tonic-gate 		}
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	(void) write(fd, &c, 1);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
189*3644994cSmeem  * script_init(): initialize script state on a given state machine
190*3644994cSmeem  *
191*3644994cSmeem  *   input: dhcp_smach_t *: the state machine
192*3644994cSmeem  *  output: void
193*3644994cSmeem  */
194*3644994cSmeem 
195*3644994cSmeem void
script_init(dhcp_smach_t * dsmp)196*3644994cSmeem script_init(dhcp_smach_t *dsmp)
197*3644994cSmeem {
198*3644994cSmeem 	dsmp->dsm_script_pid = -1;
199*3644994cSmeem 	dsmp->dsm_script_helper_pid = -1;
200*3644994cSmeem 	dsmp->dsm_script_event_id = -1;
201*3644994cSmeem 	dsmp->dsm_script_fd = -1;
202*3644994cSmeem 	dsmp->dsm_script_callback = NULL;
203*3644994cSmeem 	dsmp->dsm_script_event = NULL;
204*3644994cSmeem 	dsmp->dsm_callback_arg = NULL;
205*3644994cSmeem }
206*3644994cSmeem 
207*3644994cSmeem /*
2087c478bd9Sstevel@tonic-gate  * script_cleanup(): cleanup helper function
2097c478bd9Sstevel@tonic-gate  *
210d04ccbb3Scarlsonj  *   input: dhcp_smach_t *: the state machine
2117c478bd9Sstevel@tonic-gate  *  output: void
2127c478bd9Sstevel@tonic-gate  */
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate static void
script_cleanup(dhcp_smach_t * dsmp)215d04ccbb3Scarlsonj script_cleanup(dhcp_smach_t *dsmp)
2167c478bd9Sstevel@tonic-gate {
217*3644994cSmeem 	/*
218*3644994cSmeem 	 * We must clear dsm_script_pid prior to invoking the callback or we
219*3644994cSmeem 	 * could get in an infinite loop via async_finish().
220*3644994cSmeem 	 */
221d04ccbb3Scarlsonj 	dsmp->dsm_script_pid = -1;
222*3644994cSmeem 	dsmp->dsm_script_helper_pid = -1;
2237c478bd9Sstevel@tonic-gate 
224d04ccbb3Scarlsonj 	if (dsmp->dsm_script_fd != -1) {
225d04ccbb3Scarlsonj 		assert(dsmp->dsm_script_event_id != -1);
226d04ccbb3Scarlsonj 		(void) iu_unregister_event(eh, dsmp->dsm_script_event_id, NULL);
227d04ccbb3Scarlsonj 		(void) close(dsmp->dsm_script_fd);
2287c478bd9Sstevel@tonic-gate 
229*3644994cSmeem 		assert(dsmp->dsm_script_callback != NULL);
230*3644994cSmeem 		dsmp->dsm_script_callback(dsmp, dsmp->dsm_callback_arg);
231*3644994cSmeem 		script_init(dsmp);
2327c478bd9Sstevel@tonic-gate 		script_count--;
233*3644994cSmeem 		release_smach(dsmp);	/* hold from script_start() */
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
238*3644994cSmeem  * script_exit(): does cleanup and invokes the callback when the script exits
2397c478bd9Sstevel@tonic-gate  *
2407c478bd9Sstevel@tonic-gate  *   input: eh_t *: unused
2417c478bd9Sstevel@tonic-gate  *	    int: the end of pipe owned by dhcpagent
2427c478bd9Sstevel@tonic-gate  *	    short: unused
2437c478bd9Sstevel@tonic-gate  *	    eh_event_id_t: unused
244d04ccbb3Scarlsonj  *	    void *: the state machine
2457c478bd9Sstevel@tonic-gate  *  output: void
2467c478bd9Sstevel@tonic-gate  */
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate /* ARGSUSED */
2497c478bd9Sstevel@tonic-gate static void
script_exit(iu_eh_t * ehp,int fd,short events,iu_event_id_t id,void * arg)2507c478bd9Sstevel@tonic-gate script_exit(iu_eh_t *ehp, int fd, short events, iu_event_id_t id, void *arg)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	char c;
2537c478bd9Sstevel@tonic-gate 
254*3644994cSmeem 	if (read(fd, &c, 1) <= 0)
2557c478bd9Sstevel@tonic-gate 		c = SCRIPT_FAILED;
2567c478bd9Sstevel@tonic-gate 
257*3644994cSmeem 	if (c == SCRIPT_OK)
2587c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "script ok");
259*3644994cSmeem 	else if (c == SCRIPT_KILLED)
2607c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "script killed");
261*3644994cSmeem 	else
2627c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "script failed");
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	script_cleanup(arg);
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate /*
268*3644994cSmeem  * script_start(): tries to start a script.
269*3644994cSmeem  *		   if a script is already running, it's stopped first.
270*3644994cSmeem  *
2717c478bd9Sstevel@tonic-gate  *
272d04ccbb3Scarlsonj  *   input: dhcp_smach_t *: the state machine
2737c478bd9Sstevel@tonic-gate  *	    const char *: the event name
2747c478bd9Sstevel@tonic-gate  *	    script_callback_t: callback function
2757c478bd9Sstevel@tonic-gate  *	    void *: data to the callback function
276d04ccbb3Scarlsonj  *  output: boolean_t: B_TRUE if script starts successfully
2777c478bd9Sstevel@tonic-gate  *	    int *: the returned value of the callback function if script
2787c478bd9Sstevel@tonic-gate  *		starts unsuccessfully
2797c478bd9Sstevel@tonic-gate  */
280d04ccbb3Scarlsonj 
281d04ccbb3Scarlsonj boolean_t
script_start(dhcp_smach_t * dsmp,const char * event,script_callback_t * callback,void * arg,int * status)282d04ccbb3Scarlsonj script_start(dhcp_smach_t *dsmp, const char *event,
283d04ccbb3Scarlsonj     script_callback_t *callback, void *arg, int *status)
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	int		n;
2867c478bd9Sstevel@tonic-gate 	int		fds[2];
2877c478bd9Sstevel@tonic-gate 	pid_t		pid;
2887c478bd9Sstevel@tonic-gate 	iu_event_id_t	event_id;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	assert(callback != NULL);
2917c478bd9Sstevel@tonic-gate 
292*3644994cSmeem 	if (dsmp->dsm_script_pid != -1) {
293*3644994cSmeem 		/* script is running, stop it */
294*3644994cSmeem 		dhcpmsg(MSG_DEBUG, "script_start: stopping ongoing script");
295*3644994cSmeem 		script_stop(dsmp);
296*3644994cSmeem 	}
297*3644994cSmeem 
2987c478bd9Sstevel@tonic-gate 	if (access(SCRIPT_PATH, X_OK) == -1) {
2997c478bd9Sstevel@tonic-gate 		/* script does not exist */
3007c478bd9Sstevel@tonic-gate 		goto out;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	/*
3047c478bd9Sstevel@tonic-gate 	 * dhcpagent owns one end of the pipe and script helper process
3057c478bd9Sstevel@tonic-gate 	 * owns the other end. dhcpagent reads on the pipe; and the helper
3067c478bd9Sstevel@tonic-gate 	 * process notifies it when the script exits.
3077c478bd9Sstevel@tonic-gate 	 */
3087c478bd9Sstevel@tonic-gate 	if (pipe(fds) < 0) {
3097c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_ERROR, "script_start: can't create pipe");
3107c478bd9Sstevel@tonic-gate 		goto out;
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	if ((pid = fork()) < 0) {
3147c478bd9Sstevel@tonic-gate 		dhcpmsg(MSG_ERROR, "script_start: can't fork");
3157c478bd9Sstevel@tonic-gate 		(void) close(fds[0]);
3167c478bd9Sstevel@tonic-gate 		(void) close(fds[1]);
3177c478bd9Sstevel@tonic-gate 		goto out;
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	if (pid == 0) {
3217c478bd9Sstevel@tonic-gate 		/*
3227c478bd9Sstevel@tonic-gate 		 * SIGCHLD is ignored in dhcpagent, the helper process
3237c478bd9Sstevel@tonic-gate 		 * needs it. it calls waitpid to wait for the script to exit.
3247c478bd9Sstevel@tonic-gate 		 */
3257c478bd9Sstevel@tonic-gate 		(void) close(fds[0]);
3267c478bd9Sstevel@tonic-gate 		(void) sigset(SIGCHLD, SIG_DFL);
3277c478bd9Sstevel@tonic-gate 		(void) sigset(SIGTERM, sigterm_handler);
328d04ccbb3Scarlsonj 		run_script(dsmp, event, fds[1]);
3297c478bd9Sstevel@tonic-gate 		exit(0);
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	(void) close(fds[1]);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	/* get the script's pid */
335d04ccbb3Scarlsonj 	if (read(fds[0], &dsmp->dsm_script_pid, sizeof (pid_t)) !=
3367c478bd9Sstevel@tonic-gate 	    sizeof (pid_t)) {
3377c478bd9Sstevel@tonic-gate 		(void) kill(pid, SIGKILL);
338d04ccbb3Scarlsonj 		dsmp->dsm_script_pid = -1;
3397c478bd9Sstevel@tonic-gate 		(void) close(fds[0]);
3407c478bd9Sstevel@tonic-gate 		goto out;
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 
343d04ccbb3Scarlsonj 	dsmp->dsm_script_helper_pid = pid;
344d04ccbb3Scarlsonj 	event_id = iu_register_event(eh, fds[0], POLLIN, script_exit, dsmp);
3457c478bd9Sstevel@tonic-gate 	if (event_id == -1) {
3467c478bd9Sstevel@tonic-gate 		(void) close(fds[0]);
347d04ccbb3Scarlsonj 		script_stop(dsmp);
3487c478bd9Sstevel@tonic-gate 		goto out;
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	script_count++;
352d04ccbb3Scarlsonj 	dsmp->dsm_script_event_id = event_id;
353d04ccbb3Scarlsonj 	dsmp->dsm_script_callback = callback;
354d04ccbb3Scarlsonj 	dsmp->dsm_script_event = event;
355d04ccbb3Scarlsonj 	dsmp->dsm_callback_arg = arg;
356d04ccbb3Scarlsonj 	dsmp->dsm_script_fd = fds[0];
357d04ccbb3Scarlsonj 	hold_smach(dsmp);
358d04ccbb3Scarlsonj 	return (B_TRUE);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate out:
3617c478bd9Sstevel@tonic-gate 	/* callback won't be called in script_exit, so call it here */
362d04ccbb3Scarlsonj 	n = callback(dsmp, arg);
3637c478bd9Sstevel@tonic-gate 	if (status != NULL)
3647c478bd9Sstevel@tonic-gate 		*status = n;
3657c478bd9Sstevel@tonic-gate 
366d04ccbb3Scarlsonj 	return (B_FALSE);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate /*
3707c478bd9Sstevel@tonic-gate  * script_stop(): stops the script if it is running
3717c478bd9Sstevel@tonic-gate  *
372d04ccbb3Scarlsonj  *   input: dhcp_smach_t *: the state machine
3737c478bd9Sstevel@tonic-gate  *  output: void
3747c478bd9Sstevel@tonic-gate  */
375d04ccbb3Scarlsonj 
3767c478bd9Sstevel@tonic-gate void
script_stop(dhcp_smach_t * dsmp)377d04ccbb3Scarlsonj script_stop(dhcp_smach_t *dsmp)
3787c478bd9Sstevel@tonic-gate {
379d04ccbb3Scarlsonj 	if (dsmp->dsm_script_pid != -1) {
380d04ccbb3Scarlsonj 		assert(dsmp->dsm_script_helper_pid != -1);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 		/*
3837c478bd9Sstevel@tonic-gate 		 * sends SIGTERM to the script and asks the helper process
3847c478bd9Sstevel@tonic-gate 		 * to send SIGKILL if it does not exit after
3857c478bd9Sstevel@tonic-gate 		 * SCRIPT_TIMEOUT_GRACE seconds.
3867c478bd9Sstevel@tonic-gate 		 */
387d04ccbb3Scarlsonj 		(void) kill(dsmp->dsm_script_pid, SIGTERM);
388d04ccbb3Scarlsonj 		(void) kill(dsmp->dsm_script_helper_pid, SIGTERM);
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 
391d04ccbb3Scarlsonj 	script_cleanup(dsmp);
3927c478bd9Sstevel@tonic-gate }
393