mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-17 07:18:15 +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);
|
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 unsigned int safe_system_level = 0;
|
||||||
static void *safe_system_prev_handler;
|
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;
|
unsigned int level;
|
||||||
|
|
||||||
/* keep track of how many ast_safe_system() functions
|
|
||||||
are running at this moment
|
|
||||||
*/
|
|
||||||
ast_mutex_lock(&safe_system_lock);
|
ast_mutex_lock(&safe_system_lock);
|
||||||
level = safe_system_level++;
|
level = safe_system_level++;
|
||||||
|
|
||||||
@@ -631,6 +625,31 @@ int ast_safe_system(const char *s)
|
|||||||
safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
|
safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
|
||||||
|
|
||||||
ast_mutex_unlock(&safe_system_lock);
|
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();
|
pid = fork();
|
||||||
|
|
||||||
@@ -656,14 +675,7 @@ int ast_safe_system(const char *s)
|
|||||||
res = -1;
|
res = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_mutex_lock(&safe_system_lock);
|
ast_unreplace_sigchld();
|
||||||
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);
|
|
||||||
|
|
||||||
return res;
|
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);
|
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
|
\brief Send DTMF to a channel
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
#include "asterisk.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;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast_replace_sigchld();
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0) {
|
if (pid < 0) {
|
||||||
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
|
ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
|
||||||
|
ast_unreplace_sigchld();
|
||||||
return AGI_RESULT_FAILURE;
|
return AGI_RESULT_FAILURE;
|
||||||
}
|
}
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
@@ -1781,7 +1784,7 @@ static int agi_handle_command(struct ast_channel *chan, AGI *agi, char *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#define RETRY 3
|
#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;
|
struct ast_channel *c;
|
||||||
int outfd;
|
int outfd;
|
||||||
@@ -1830,6 +1833,7 @@ static enum agi_result run_agi(struct ast_channel *chan, char *request, AGI *agi
|
|||||||
returnstatus = -1;
|
returnstatus = -1;
|
||||||
if (option_verbose > 2)
|
if (option_verbose > 2)
|
||||||
ast_verbose(VERBOSE_PREFIX_3 "AGI Script %s completed, returning %d\n", request, returnstatus);
|
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 */
|
/* No need to kill the pid anymore, since they closed us */
|
||||||
pid = -1;
|
pid = -1;
|
||||||
break;
|
break;
|
||||||
@@ -1976,13 +1980,18 @@ static int agi_exec_full(struct ast_channel *chan, void *data, int enhanced, int
|
|||||||
#endif
|
#endif
|
||||||
res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
|
res = launch_script(argv[0], argv, fds, enhanced ? &efd : NULL, &pid);
|
||||||
if (res == AGI_RESULT_SUCCESS) {
|
if (res == AGI_RESULT_SUCCESS) {
|
||||||
|
int status = 0;
|
||||||
agi.fd = fds[1];
|
agi.fd = fds[1];
|
||||||
agi.ctrl = fds[0];
|
agi.ctrl = fds[0];
|
||||||
agi.audio = efd;
|
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]);
|
close(fds[1]);
|
||||||
if (efd > -1)
|
if (efd > -1)
|
||||||
close(efd);
|
close(efd);
|
||||||
|
ast_unreplace_sigchld();
|
||||||
}
|
}
|
||||||
ast_localuser_remove(me, u);
|
ast_localuser_remove(me, u);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user