/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#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 "agent.h"
#include "script_handler.h"
#include "states.h"
#include "interface.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.
*/
/*
* 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 SIGALRM
*
* input: int: signal the handler was called with
* output: void
*/
/* ARGSUSED */
static void
{
/* 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
{
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: dhcp_smach_t *: the state machine
* const char *: the event name
* int: the pipe end owned by the script helper process
* output: void
*/
static void
{
int n;
char c;
char *path;
char *name;
return;
if (pid == 0) {
path = SCRIPT_PATH;
/* close all files */
closefrom(0);
_exit(127);
(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_init(): initialize script state on a given state machine
*
* input: dhcp_smach_t *: the state machine
* output: void
*/
void
{
}
/*
* script_cleanup(): cleanup helper function
*
* input: dhcp_smach_t *: the state machine
* output: void
*/
static void
{
/*
* We must clear dsm_script_pid prior to invoking the callback or we
* could get in an infinite loop via async_finish().
*/
script_count--;
}
}
/*
* script_exit(): does cleanup and invokes the callback when the script exits
*
* input: eh_t *: unused
* int: the end of pipe owned by dhcpagent
* short: unused
* eh_event_id_t: unused
* void *: the state machine
* output: void
*/
/* ARGSUSED */
static void
{
char c;
c = SCRIPT_FAILED;
if (c == SCRIPT_OK)
else if (c == SCRIPT_KILLED)
else
}
/*
* script_start(): tries to start a script.
* if a script is already running, it's stopped first.
*
*
* input: dhcp_smach_t *: the state machine
* const char *: the event name
* script_callback_t: callback function
* void *: data to the callback function
* output: boolean_t: B_TRUE if script starts successfully
* int *: the returned value of the callback function if script
* starts unsuccessfully
*/
{
int n;
/* script is running, stop it */
}
/* script does not exist */
goto out;
}
/*
* 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 (B_TRUE);
out:
/* callback won't be called in script_exit, so call it here */
*status = n;
return (B_FALSE);
}
/*
* script_stop(): stops the script if it is running
*
* input: dhcp_smach_t *: the state machine
* 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.
*/
}
}