Add the ability to retrieve the exit code of the forked AGI process. If there

is an error executing the AGI script, or the AGI script itself returns a
non-zero value, the AGISTATUS variable will now be set to FAILURE instead of
SUCCESS.


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@30328 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Russell Bryant 19 years ago
parent 35d729fb40
commit 238cdb249f

@ -608,21 +608,15 @@ static void null_sig_handler(int signal)
}
AST_MUTEX_DEFINE_STATIC(safe_system_lock);
/*! Keep track of how many threads are currently trying to wait*() on
* a child process */
static unsigned int safe_system_level = 0;
static void *safe_system_prev_handler;
int ast_safe_system(const char *s)
void ast_replace_sigchld(void)
{
pid_t pid;
int x;
int res;
struct rusage rusage;
int status;
unsigned int level;
/* keep track of how many ast_safe_system() functions
are running at this moment
*/
ast_mutex_lock(&safe_system_lock);
level = safe_system_level++;
@ -631,6 +625,31 @@ int ast_safe_system(const char *s)
safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
ast_mutex_unlock(&safe_system_lock);
}
void ast_unreplace_sigchld(void)
{
unsigned int level;
ast_mutex_lock(&safe_system_lock);
level = --safe_system_level;
/* only restore the handler if we are the last one */
if (level == 0)
signal(SIGCHLD, safe_system_prev_handler);
ast_mutex_unlock(&safe_system_lock);
}
int ast_safe_system(const char *s)
{
pid_t pid;
int x;
int res;
struct rusage rusage;
int status;
ast_replace_sigchld();
pid = fork();
@ -656,14 +675,7 @@ int ast_safe_system(const char *s)
res = -1;
}
ast_mutex_lock(&safe_system_lock);
level = --safe_system_level;
/* only restore the handler if we are the last one */
if (level == 0)
signal(SIGCHLD, safe_system_prev_handler);
ast_mutex_unlock(&safe_system_lock);
ast_unreplace_sigchld();
return res;
}

@ -119,6 +119,27 @@ int ast_app_messagecount(const char *context, const char *mailbox, const char *f
*/
int ast_safe_system(const char *s);
/*!
* \brief Replace the SIGCHLD handler
*
* Normally, Asterisk has a SIGCHLD handler that is cleaning up all zombie
* processes from forking elsewhere in Asterisk. However, if you want to
* wait*() on the process to retrieve information about it's exit status,
* then this signal handler needs to be temporaraly replaced.
*
* Code that executes this function *must* call ast_unreplace_sigchld()
* after it is finished doing the wait*().
*/
void ast_replace_sigchld(void);
/*!
* \brief Restore the SIGCHLD handler
*
* This function is called after a call to ast_replace_sigchld. It restores
* the SIGCHLD handler that cleans up any zombie processes.
*/
void ast_unreplace_sigchld(void);
/*!
\brief Send DTMF to a channel

@ -39,6 +39,7 @@
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include "asterisk.h"
@ -275,9 +276,11 @@ static enum agi_result launch_script(char *script, char *argv[], int *fds, int *
return AGI_RESULT_FAILURE;
}
}
ast_replace_sigchld();
pid = fork();
if (pid < 0) {
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
ast_unreplace_sigchld();
return AGI_RESULT_FAILURE;
}
if (!pid) {
@ -1781,7 +1784,7 @@ static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
return 0;
}
#define RETRY 3
static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int dead)
static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi, int pid, int *status, int dead)
{
struct ast_channel *c;
int outfd;
@ -1830,6 +1833,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
returnstatus = -1;
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
waitpid(pid, status, 0);
/* No need to kill the pid anymore, since they closed us */
pid = -1;
break;
@ -1976,13 +1980,18 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int
#endif
res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
if (res == AGI_RESULT_SUCCESS) {
int status = 0;
agi.fd = fds[1];
agi.ctrl = fds[0];
agi.audio = efd;
res = run_agi(chan, argv[0], &agi, pid, dead);
res = run_agi(chan, argv[0], &agi, pid, &status, dead);
/* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
if (res == AGI_RESULT_SUCCESS && status)
res = AGI_RESULT_FAILURE;
close(fds[1]);
if (efd > -1)
close(efd);
ast_unreplace_sigchld();
}
ast_localuser_remove(me, u);

Loading…
Cancel
Save