script_handler.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <time.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <dhcpmsg.h>
#include "script_handler.h"
/*
* scripts are directly managed by a script helper process. dhcpagent creates
* the helper process and it, in turn, creates a process to run the script
* dhcpagent owns one end of a pipe and the helper process owns the other end
* the helper process calls waitpid to wait for the script to exit. an alarm
* is set for SCRIPT_TIMEOUT seconds. If the alarm fires, SIGTERM is sent to
* the script process and a second alarm is set for SCRIPT_TIMEOUT_GRACE. if
* the second alarm fires, SIGKILL is sent to forcefully kill the script. when
* script exits, the helper process notifies dhcpagent by closing its end
* of the pipe.
*/
unsigned int script_count;
/*
* the signal to send to the script process. it is a global variable
* to this file as sigterm_handler needs it.
*/
static int script_signal = SIGTERM;
/*
* script's absolute timeout value. the first timeout is set to SCRIPT_TIMEOUT
* seconds from the time it is started. SIGTERM is sent on the first timeout
* the second timeout is set to SCRIPT_TIMEOUT_GRACE from the first timeout
* and SIGKILL is sent on the second timeout.
*/
/*
* sigalarm_handler(): signal handler for SIGARLM
*
* input: int: signal the handler was called with
* output: void
*/
/* ARGSUSED */
static void
sigalarm_handler(int sig)
{
/* set a another alarm if it fires too early */
}
/*
* sigterm_handler(): signal handler for SIGTERM, fired when dhcpagent wants
* to stop the script
* input: int: signal the handler was called with
* output: void
*/
/* ARGSUSED */
static void
sigterm_handler(int sig)
{
if (script_signal != SIGKILL) {
/* send SIGKILL SCRIPT_TIMEOUT_GRACE seconds from now */
(void) alarm(SCRIPT_TIMEOUT_GRACE);
}
}
/*
* run_script(): it forks a process to execute the script
*
* input: struct ifslist *: the interface
* const char *: the event name
* int: the pipe end owned by the script helper process
* output: void
*/
static void
{
int n;
char c;
char *name;
extern int errno;
return;
}
if (pid == 0) {
/* close all files */
closefrom(0);
exit(-1);
(void) dup2(n, STDOUT_FILENO);
(void) dup2(n, STDERR_FILENO);
_exit(127);
}
/*
* the first timeout fires SCRIPT_TIMEOUT seconds from now.
*/
(void) alarm(SCRIPT_TIMEOUT);
/*
* pass script's pid to dhcpagent.
*/
for (;;) {
/* script has exited */
c = SCRIPT_OK;
break;
}
return;
}
if (script_signal == SIGKILL) {
c = SCRIPT_KILLED;
break;
}
(void) alarm(SCRIPT_TIMEOUT_GRACE);
}
}
}
/*
* script_cleanup(): cleanup helper function
*
* input: struct ifslist *: the interface
* output: void
*/
static void
{
(void) release_ifs(ifsp);
script_count--;
}
}
/*
* script_exit(): does cleanup and invokes callback when script exits
*
* input: eh_t *: unused
* int: the end of pipe owned by dhcpagent
* short: unused
* eh_event_id_t: unused
* void *: the interface
* output: void
*/
/* ARGSUSED */
static void
{
char c;
c = SCRIPT_FAILED;
}
if (c == SCRIPT_OK) {
} else if (c == SCRIPT_KILLED) {
} else {
}
}
/*
* script_start(): tries to run the script
*
* input: struct ifslist *: the interface
* const char *: the event name
* script_callback_t: callback function
* void *: data to the callback function
* output: int: 1 if script starts successfully
* int *: the returned value of the callback function if script
* starts unsuccessfully
*/
int
{
int n;
int fds[2];
/* script does not exist */
goto out;
}
/* script is running, stop it */
}
/*
* dhcpagent owns one end of the pipe and script helper process
* owns the other end. dhcpagent reads on the pipe; and the helper
* process notifies it when the script exits.
*/
goto out;
}
goto out;
}
if (pid == 0) {
/*
* SIGCHLD is ignored in dhcpagent, the helper process
* needs it. it calls waitpid to wait for the script to exit.
*/
exit(0);
}
/* get the script's pid */
sizeof (pid_t)) {
goto out;
}
if (event_id == -1) {
goto out;
}
script_count++;
return (1);
out:
/* callback won't be called in script_exit, so call it here */
*status = n;
return (0);
}
/*
* script_stop(): stops the script if it is running
*
* input: struct ifslist *: the interface
* output: void
*/
void
{
/*
* sends SIGTERM to the script and asks the helper process
* to send SIGKILL if it does not exit after
* SCRIPT_TIMEOUT_GRACE seconds.
*/
}
}