mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-29 18:19:30 +00:00
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
This commit is contained in:
46
asterisk.c
46
asterisk.c
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user