<!-- Module User's Guide -->

<chapter>

	<title>&adminguide;</title>

	<section id="overview" xreflabel="Overview">
	<title>Overview</title>
	<para>
		The Exec module enables the execution of external commands from the
		&osips; script. Any valid shell commands are accepted. The final input
		string is evaluated and executed using the "/bin/sh" symlink/binary.
		&osips; may additionally pass a lot more information about the request
		using environment variables:
	</para>
	<itemizedlist>
		<listitem>
		<para>
			SIP_HF_&lt;hf_name&gt; contains value of each header field in
			request. If a header field occurred multiple times, values are
			concatenated and comma-separated. &lt;hf_name&gt; is in capital
			letters. Ff a header-field name occurred in compact form,
			&lt;hf_name&gt; is canonical.
		</para>
		</listitem>
		<listitem>
		<para>
			SIP_TID is transaction identifier. All request retransmissions or
			CANCELs/ACKs associated with a previous INVITE result in the same
			value.
		</para>
		</listitem>
		<listitem>
		<para>
			SIP_DID is dialog identifier, which is the same as to-tag.
			Initially, it is empty.
		</para>
		</listitem>
		<listitem>
		<para>
			SIP_SRCIP is source &ip; address from which request came.
		</para>
		</listitem>
		<listitem>
		<para>
			SIP_ORURI is original request &uri;.
		</para>
		</listitem>
		<listitem>
		<para>
			SIP_RURI is <emphasis>current</emphasis> request &uri; (if
			unchanged, equal to original).
		</para>
		</listitem>
		<listitem>
		<para>
			SIP_USER is userpart of <emphasis>current</emphasis> request &uri;.
		</para>
		</listitem>
		<listitem>
		<para>
			SIP_OUSER is userpart of original request &uri;.
		</para>
		</listitem>
	</itemizedlist>
	<para>
		NOTE: Any environment variables which are given to the exec module
		functions must be specified using the '$$' delimiter (e.g., $$SIP_OUSER),
		otherwise they will be evaluated as &osips; pseudo-variables,
		throwing scripting errors.
	</para>
	</section>

	<section id="dependencies" xreflabel="Dependencies">
	<title>Dependencies</title>
	<section>
		<title>&osips; Modules</title>
		<para>
		The following  modules must be loaded before this module:
			<itemizedlist>
			<listitem>
			<para>
				<emphasis>No dependencies on other &osips; modules</emphasis>.
			</para>
			</listitem>
			</itemizedlist>
		</para>
	</section>
	<section>
		<title>External Libraries or Applications</title>
		<para>
		The following libraries or applications must be installed before running
		&osips; with this module loaded:
			<itemizedlist>
			<listitem>
			<para>
				<emphasis>None</emphasis>.
			</para>
			</listitem>
			</itemizedlist>
		</para>
	</section>
	</section>

	<section id="exported_parameters" xreflabel="Exported Parameters">
	<title>Exported Parameters</title>
	<section id="param_setvars" xreflabel="setvars">
		<title><varname>setvars</varname> (integer)</title>
		<para>
		Set to 1 to enable setting all above-mentioned environment variables
		for all executed commands.
		</para>
		<para>
		<emphasis role='bold'>WARNING: Before enabling this parameter, make sure
		your "/bin/sh" is safe from the Shellshock bash vulnerability!!! </emphasis>
		</para>
		<para>
		<emphasis>
			Default value is 0 (disabled).
		</emphasis>
		</para>
		<example>
		<title>Set <quote>setvars</quote> parameter</title>
		<programlisting format="linespecific">
...
modparam("exec", "setvars", 1)
...
</programlisting>
		</example>
	</section>
	<section id="param_time_to_kill" xreflabel="time_to_kill">
		<title><varname>time_to_kill</varname> (integer)</title>
		<para>
		If set, this parameter specifies the longest time (in seconds) that a
		program is allowed to execute. Once this duration is exceeded, the
		program is terminated (SIGTERM).
		</para>
		<para>
		NOTE: due to internal limitations, a SIGTERM will actually be sent to
		<emphasis role='bold'>all</emphasis> job pids once the "time_to_kill"
		expiration timeout hits. On a standard system, this should have no
		side-effects, as pids are monotonically increasing in a slow manner,
		and OpenSIPS should run under the "opensips" user, thus rendering it
		unable to terminate non-child processes. If this is not the case on
		your system, do not use the OpenSIPS "time_to_kill" feature -- rather
		implement it within your external app!
		</para>
		<para>
		<emphasis>
			Default value is 0 (disabled).
		</emphasis>
		</para>
		<example>
		<title>Set <quote>time_to_kill</quote> parameter</title>
		<programlisting format="linespecific">
...
modparam("exec", "time_to_kill", 20)
...
</programlisting>
		</example>
	</section>

	</section>
	<section id="exported_functions" xreflabel="exported_functions">
	<title>Exported Functions</title>
	<section id="func_exec" xreflabel="exec()">
		<title>
		<function moreinfo="none">exec(command, [stdin], [stdout], [stderr], [envavp])</function>
		</title>
		<para>
		Executes an external command. The input is passed to the standard input of the new
		process, if specified, and the output is saved in the output variable.
		</para>
		<para>
		The function waits for the external script until it provided all its output (not
		necessary to actually finish). If no output (standard output or standard error)
		is required by the function, it will not block at all - it will simply launch the
		external script and continue the script.
		</para>
		<para>Meaning of the parameters is as follows:</para>
		<itemizedlist>
		<listitem>
			<para><emphasis>command (string)</emphasis> - command to be executed
			</para>
		</listitem>
		<listitem>
			<para><emphasis>stdin (string, optional)</emphasis> - string to be
				passed to the standard input of the command
			</para>
		</listitem>
		<listitem>
			<para><emphasis>stdout (var, optional)</emphasis> - optional
				output variable which will hold the standard output of the
				process
			</para>
		</listitem>
		<listitem>
			<para><emphasis>stderr (var, optional)</emphasis> - optional
				output variable which will hold the standard error of the
				process
			</para>
		</listitem>
		<listitem>
			<para><emphasis>envavp (var, optional)</emphasis> - optional AVP
				which holds the values for the
			environment variables to be passed for the command. The names of the environment
			variables will be "OSIPS_EXEC_#", where "#" starts from 0. For example, if we
			push two values (e.g. "b" and "a") into an AVP variable, which acts like a stack,
			OSIPS_EXEC_0 will hold "a", while OSIPS_EXEC_1 will hold "b".
			</para>
		</listitem>
		</itemizedlist>
		<para>
		NOTE: If expecting a multi-line formatted output, you should use $avp
		variables for the "stdout" and "stderr" parameters, to avoid only
		receiving the last lines of each stream.
		</para>
		<para>
		WARNING: any OpenSIPS pseudo-vars which may contain special bourne shell (sh/bash)
		characters should be placed inside quotes, e.g.
		exec("update-stats.sh '$(ct{re.subst,/'//g})'");
		</para>
		<para>
		WARNING: "stdin"/"stdout"/"stderr" parameters are not designed for large amounts of
		data, so one should be careful when using them. Because of the basic implementation,
		filled up pipes could cause a read deadlock.
		</para>
		<para>
		This function can be used from REQUEST_ROUTE, FAILURE_ROUTE,
		LOCAL_ROUTE, STARTUP_ROUTE, TIMER_ROUTE, EVENT_ROUTE, ONREPLY_ROUTE.
		</para>
		<example>
		<title><function moreinfo="none">exec</function> usage</title>
		<programlisting format="linespecific">
...
$avp(env) = "a";
$avp(env) = "b";
exec("ls -l", , $var(out), $var(err), $avp(env));
xlog("The output is $var(out)\n");
xlog("Received the following error\n$var(err)");
...
$var(input) = "input";
exec("/home/../myscript.sh", "this is my $var(input) for exec\n", , , $avp(env));
...
</programlisting>
		</example>
	</section>

	</section>

	<section>
	<title>Exported Asyncronous Functions</title>
	<section id="afunc_exec" xreflabel="exec()">
		<title>
		<function moreinfo="none">exec(command, [stdin], [stdout], [stderr], [envavp])</function>
		</title>
		<para>
		Executes an external command. This function does exactly the same as
		<xref linkend="func_exec"/> (in terms of input, output and processing),
		but in an asynchronous way. The script execution is suspended until
		the external script provided all its output. OpenSIPS waits for the
		external script to close its output stream, not necessarily to
		terminate (so the script may still be running when OpenSIPS
		resumes the script execution on "seeing" EOF on the the output stream)
		</para>
		NOTE: if the stdout variable is missing, OpenSIPS will assume that the
		output of the external script is not needed and it will NOT WAIT at
		all for the script. So, if triggered via "launch()", there will be no 
		asynchronous waiting, so no resume route triggering!!
		<para>
		</para>
		<para>
		NOTE: this function ignore the "stderr" parameter for now - the
		asynchronous waiting is done only on the output stream !! This may
		be fixed in the following versions.
		</para>
		<para>
		To read and understand more on the asynchronous functions, how to use
		them and what are their advantages, please refer to the OpenSIPS 
		online Manual.
		</para>
		<example>
		<title><function moreinfo="none">async exec</function> usage</title>
		<programlisting format="linespecific">
{
...
async(exec("ruri-changer.sh", $ru, $ru), resume);
}

route [resume] {
...
}
</programlisting>
		</example>
	</section>
	</section>

	<section>
	<title>Known Issues</title>
	<para>
		When imposing an execution timeout using
		<emphasis role='bold'><xref linkend="param_time_to_kill"/></emphasis>,
		make sure your "/bin/sh" is a shell which does not fork when executed,
		case in which the job itself will not be killed, but rather its parent shell,
		while the job is silently inherited by "init" and will continue to run.
		"/bin/dash" is one of these troublesome shell environments.
	</para>
	</section>
</chapter>

