Newer
Older
* Asterisk -- An open source telephony toolkit.
Kevin P. Fleming
committed
* Copyright (C) 1999 - 2006, Digium, Inc.
* Mark Spencer <markster@digium.com>
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
*
* \brief Standard Command Line Interface
*
* \author Mark Spencer <markster@digium.com>
Kevin P. Fleming
committed
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <sys/signal.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
Russell Bryant
committed
#include <regex.h>
Kevin P. Fleming
committed
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"
#include "asterisk/linkedlists.h"
Kevin P. Fleming
committed
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/utils.h"
Russell Bryant
committed
#include "asterisk/app.h"
Kevin P. Fleming
committed
#include "asterisk/lock.h"
#include "asterisk/threadstorage.h"
Mark Spencer
committed
extern unsigned long global_fin, global_fout;
Russell Bryant
committed
AST_THREADSTORAGE(ast_cli_buf);
/*! \brief Initial buffer size for resulting strings in ast_cli() */
#define AST_CLI_INITLEN 256
Russell Bryant
committed
int res;
struct ast_dynamic_str *buf;
if (!(buf = ast_dynamic_str_thread_get(&ast_cli_buf, AST_CLI_INITLEN)))
res = ast_dynamic_str_thread_set_va(&buf, 0, &ast_cli_buf, fmt, ap);
if (res != AST_DYNSTR_BUILD_FAILED)
ast_carefulwrite(fd, buf->str, strlen(buf->str), 100);
Kevin P. Fleming
committed
static AST_LIST_HEAD_STATIC(helpers, ast_cli_entry);
"Usage: module load <module name>\n"
" Loads the specified module into Asterisk.\n";
static char unload_help[] =
"Usage: module unload [-f|-h] <module name>\n"
Mark Spencer
committed
" Unloads the specified module from Asterisk. The -f\n"
" option causes the module to be unloaded even if it is\n"
" in use (may cause a crash) and the -h module causes the\n"
" module to be unloaded even if the module says it cannot, \n"
" which almost always will cause a crash.\n";
static char help_help[] =
"Usage: help [topic]\n"
" When called with a topic as an argument, displays usage\n"
Mark Spencer
committed
" information on the given command. If called without a\n"
" topic, it provides a list of commands.\n";
static char chanlist_help[] =
"Usage: core show channels [concise|verbose]\n"
Mark Spencer
committed
" Lists currently defined channels and some information about them. If\n"
" 'concise' is specified, the format is abridged and in a more easily\n"
" machine parsable format. If 'verbose' is specified, the output includes\n"
" more and longer fields.\n";
"Usage: module reload [module ...]\n"
" Reloads configuration files for all listed modules which support\n"
" reloading, or for all supported modules if none are listed.\n";
Joshua Colp
committed
static char logger_mute_help[] =
"Usage: logger mute\n"
" Disables logging output to the current console, making it possible to\n"
" gather information without being disturbed by scrolling lines.\n";
static char softhangup_help[] =
"Usage: soft hangup <channel>\n"
Mark Spencer
committed
" Request that a channel be hung up. The hangup takes effect\n"
" the next time the driver reads or writes from the channel\n";
Russell Bryant
committed
static char group_show_channels_help[] =
"Usage: group show channels [pattern]\n"
Russell Bryant
committed
" Lists all currently active channels with channel group(s) specified.\n"
" Optional regular expression pattern is matched to group names for each\n"
" channel.\n";
static int handle_load(int fd, int argc, char *argv[])
{
/* "module load <mod>" */
if (argc != 3)
return RESULT_SHOWUSAGE;
if (ast_load_resource(argv[2])) {
ast_cli(fd, "Unable to load module %s\n", argv[2]);
return RESULT_FAILURE;
}
return RESULT_SUCCESS;
}
static int handle_load_deprecated(int fd, int argc, char *argv[])
{
/* I know it is nasty, but they do look very similar, and we never access argv[0] */
return handle_load(fd, argc+1, argv - 1);
}
static int handle_reload(int fd, int argc, char *argv[])
{
/* "module reload [mod_1 ... mod_N]" */
struct ast_cli_entry *e = (struct ast_cli_entry *)argv[-1];
if (argc == e->args)
ast_module_reload(NULL);
else {
int x;
for (x = e->args; x < argc; x++) {
int res = ast_module_reload(argv[x]);
switch(res) {
case 0:
ast_cli(fd, "No such module '%s'\n", argv[x]);
break;
case 1:
ast_cli(fd, "Module '%s' does not support reload\n", argv[x]);
break;
}
}
return RESULT_SUCCESS;
}
static int handle_reload_deprecated(int fd, int argc, char *argv[])
{
return handle_reload(fd, argc+1, argv-1); /* see comment in handle_load_deprecated() */
}
static int handle_verbose(int fd, int argc, char *argv[])
{
/* "core set verbose [atleast] <n>" */
int newlevel;
int atleast = 0;
struct ast_cli_entry *e = (struct ast_cli_entry *)argv[-1];
static char *choices[] = { "off", "atleast", NULL };
struct ast_cli_args *a;
switch (argc) {
case CLI_CMD_STRING:
return (int)"core set verbose";
case CLI_USAGE:
return (int)
"Usage: core set verbose [atleast] <level>\n"
" core set verbose off\n"
" Sets level of verbose messages to be displayed. 0 or off means\n"
" no messages should be displayed. Equivalent to -v[v[v...]]\n"
" on startup\n";
case CLI_GENERATE:
a = (struct ast_cli_args *)argv[0];
if (a->pos > e->args)
return (int)ast_cli_complete(a->word, choices, a->n);
}
/* all the above return, so we proceed with the handler.
* we are guaranteed to be called with argc >= e->args;
*/
if (argc < e->args + 1)
return RESULT_SHOWUSAGE;
if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
newlevel = 0;
goto done;
}
if (!strcasecmp(argv[e->args], "atleast"))
atleast = 1;
if (argc != e->args + atleast + 1)
return RESULT_SHOWUSAGE;
if (sscanf(argv[e->args + atleast], "%d", &newlevel) != 1)
return RESULT_SHOWUSAGE;
done:
if (!atleast || newlevel > option_verbose)
option_verbose = newlevel;
if (oldval > 0 && option_verbose == 0)
ast_cli(fd, "Verbosity is now OFF\n");
else if (option_verbose > 0) {
if (oldval == option_verbose)
ast_cli(fd, "Verbosity is at least %d\n", option_verbose);
else
ast_cli(fd, "Verbosity was %d and is now %d\n", oldval, option_verbose);
}
return RESULT_SUCCESS;
}
static int handle_set_debug(int fd, int argc, char *argv[])
struct ast_cli_entry *e = (struct ast_cli_entry *)argv[-1];
int oldval = option_debug;
int newlevel;
static char *choices[] = { "off", "atleast", NULL };
struct ast_cli_args *a;
switch (argc) {
case CLI_CMD_STRING:
return (int)"core set debug";
case CLI_USAGE:
return (int)
"Usage: core set debug [atleast] <level> [filename]\n"
" core set debug off\n"
" Sets level of core debug messages to be displayed. 0 or 'off' means\n"
" no messages should be displayed. Equivalent to -d[d[d...]]\n"
" on startup. If filename is specified, debugging will be\n"
" limited to just that file.\n";
case CLI_GENERATE:
a = (struct ast_cli_args *)argv[0];
if (a->pos > e->args)
return (int)ast_cli_complete(a->word, choices, a->n);
}
/* all the above return, so we proceed with the handler.
* we are guaranteed to be called with argc >= e->args;
if (argc < e->args + 1)
if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
newlevel = 0;
goto done;
}
if (!strcasecmp(argv[e->args], "atleast"))
if (argc < e->args + atleast + 1 || argc > e->args + atleast + 2)
return RESULT_SHOWUSAGE;
if (sscanf(argv[e->args + atleast], "%d", &newlevel) != 1)
return RESULT_SHOWUSAGE;
if (argc == e->args + atleast + 1) {
debug_filename[0] = '\0';
ast_copy_string(debug_filename, argv[e->args + atleast + 1], sizeof(debug_filename));
done:
if (!atleast || newlevel > option_debug)
option_debug = newlevel;
if (oldval > 0 && option_debug == 0)
ast_cli(fd, "Core debug is now OFF\n");
else if (option_debug > 0) {
if (filename) {
if (oldval == option_debug)
ast_cli(fd, "Core debug is at least %d, file '%s'\n", option_debug, filename);
else
ast_cli(fd, "Core debug was %d and is now %d, file '%s'\n", oldval, option_debug, filename);
} else {
if (oldval == option_debug)
ast_cli(fd, "Core debug is at least %d\n", option_debug);
else
ast_cli(fd, "Core debug was %d and is now %d\n", oldval, option_debug);
}
}
return RESULT_SUCCESS;
}
Joshua Colp
committed
static int handle_logger_mute(int fd, int argc, char *argv[])
{
if (argc != 2)
return RESULT_SHOWUSAGE;
ast_console_toggle_mute(fd);
Joshua Colp
committed
return RESULT_SUCCESS;
}
static int handle_unload(int fd, int argc, char *argv[])
{
/* "module unload mod_1 [mod_2 .. mod_N]" */
int x;
int force = AST_FORCE_SOFT;
if (argc < 3)
return RESULT_SHOWUSAGE;
for (x = 2; x < argc; x++) {
if (argv[x][0] == '-') {
switch(argv[x][1]) {
case 'f':
force = AST_FORCE_FIRM;
break;
case 'h':
force = AST_FORCE_HARD;
break;
default:
return RESULT_SHOWUSAGE;
}
} else if (x != argc - 1)
return RESULT_SHOWUSAGE;
else if (ast_unload_resource(argv[x], force)) {
ast_cli(fd, "Unable to unload resource %s\n", argv[x]);
return RESULT_FAILURE;
}
}
return RESULT_SUCCESS;
}
static int handle_unload_deprecated(int fd, int argc, char *argv[])
{
return handle_unload(fd, argc+1, argv - 1); /* see commment in handle_load_deprecated() */
}
#define MODLIST_FORMAT "%-30s %-40.40s %-10d\n"
#define MODLIST_FORMAT2 "%-30s %-40.40s %-10s\n"
AST_MUTEX_DEFINE_STATIC(climodentrylock);
static int modlist_modentry(const char *module, const char *description, int usecnt, const char *like)
/* Comparing the like with the module */
if (strcasestr(module, like) ) {
ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt);
static void print_uptimestr(int fd, time_t timeval, const char *prefix, int printsec)
int x; /* the main part - years, weeks, etc. */
char timestr[256]="", *s = timestr;
size_t maxbytes = sizeof(timestr);
Mark Spencer
committed
#define MINUTE (SECOND*60)
#define HOUR (MINUTE*60)
#define DAY (HOUR*24)
#define WEEK (DAY*7)
#define YEAR (DAY*365)
#define ESS(x) ((x == 1) ? "" : "s") /* plural suffix */
#define NEEDCOMMA(x) ((x)? ",": "") /* define if we need a comma */
if (timeval < 0) /* invalid, nothing to show */
return;
if (printsec) { /* plain seconds output */
ast_build_string(&s, &maxbytes, "%lu", (u_long)timeval);
timeval = 0; /* bypass the other cases */
}
x = (timeval / YEAR);
timeval -= (x * YEAR);
ast_build_string(&s, &maxbytes, "%d year%s%s ", x, ESS(x),NEEDCOMMA(timeval));
x = (timeval / WEEK);
timeval -= (x * WEEK);
ast_build_string(&s, &maxbytes, "%d week%s%s ", x, ESS(x),NEEDCOMMA(timeval));
x = (timeval / DAY);
timeval -= (x * DAY);
ast_build_string(&s, &maxbytes, "%d day%s%s ", x, ESS(x),NEEDCOMMA(timeval));
x = (timeval / HOUR);
timeval -= (x * HOUR);
ast_build_string(&s, &maxbytes, "%d hour%s%s ", x, ESS(x),NEEDCOMMA(timeval));
Mark Spencer
committed
if (timeval > MINUTE) {
x = (timeval / MINUTE);
timeval -= (x * MINUTE);
ast_build_string(&s, &maxbytes, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval));
x = timeval;
if (x > 0)
ast_build_string(&s, &maxbytes, "%d second%s ", x, ESS(x));
if (timestr[0] != '\0')
ast_cli(fd, "%s: %s\n", prefix, timestr);
}
static int handle_showuptime(int fd, int argc, char *argv[])
{
Luigi Rizzo
committed
struct ast_cli_entry *e = (struct ast_cli_entry *)argv[-1];
time_t curtime;
int printsec;
struct ast_cli_args *a;
switch (argc) {
case CLI_CMD_STRING:
return (int)"core show uptime";
case CLI_USAGE:
return (int)
"Usage: core show uptime [seconds]\n"
" Shows Asterisk uptime information.\n"
" The seconds word returns the uptime in seconds only.\n";
Luigi Rizzo
committed
case CLI_GENERATE:
a = (struct ast_cli_args *)argv[0];
return (int)((a->pos > e->args || a->n > 0) ? NULL : "seconds");
}
/* regular handler */
if (argc == e->args+1 && !strcasecmp(argv[e->args],"seconds"))
printsec = 1;
else if (argc == e->args)
printsec = 0;
else
return RESULT_SHOWUSAGE;
Luigi Rizzo
committed
curtime = time(NULL);
if (ast_startuptime)
print_uptimestr(fd, curtime - ast_startuptime, "System uptime", printsec);
if (ast_lastreloadtime)
print_uptimestr(fd, curtime - ast_lastreloadtime, "Last reload", printsec);
static int handle_modlist(int fd, int argc, char *argv[])
{
struct ast_cli_entry *e = (struct ast_cli_entry *)argv[-1];
char *like;
struct ast_cli_args *a;
switch(argc) {
case CLI_CMD_STRING:
return (int)"module show";
case CLI_USAGE:
return (int)
"Usage: module show [like keyword]\n"
" Shows Asterisk modules currently in use, and usage statistics.\n";
case CLI_GENERATE:
a = (struct ast_cli_args *)argv[0];
if (a->pos == e->args)
return (int)(a->n == 0 ? strdup("like") : NULL);
else if (a->pos == e->args+1 && strcasestr(a->line," like "))
return (int)ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
else
return (int)NULL;
/* all the above return, so we proceed with the handler.
* we are guaranteed to have argc >= e->args
*/
if (argc == e->args)
like = "";
else if (argc == e->args + 2 && !strcmp(argv[e->args],"like"))
like = argv[e->args + 1];
else
return RESULT_SHOWUSAGE;
ast_mutex_lock(&climodentrylock);
climodentryfd = fd; /* global, protected by climodentrylock */
ast_cli(fd, MODLIST_FORMAT2, "Module", "Description", "Use Count");
ast_cli(fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
ast_mutex_unlock(&climodentrylock);
Mark Spencer
committed
#undef MODLIST_FORMAT
#undef MODLIST_FORMAT2
/* core show channels [concise|verbose] */
static int handle_chanlist(int fd, int argc, char *argv[])
{
Mark Spencer
committed
#define FORMAT_STRING "%-20.20s %-20.20s %-7.7s %-30.30s\n"
#define FORMAT_STRING2 "%-20.20s %-20.20s %-7.7s %-30.30s\n"
Kevin P. Fleming
committed
#define CONCISE_FORMAT_STRING "%s!%s!%s!%d!%s!%s!%s!%s!%s!%d!%s!%s\n"
Mark Spencer
committed
#define VERBOSE_FORMAT_STRING "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-20.20s\n"
#define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-20.20s\n"
struct ast_channel *c = NULL;
Mark Spencer
committed
char durbuf[10] = "-";
char locbuf[40];
char appdata[40];
int duration;
int durh, durm, durs;
int numchans = 0, concise = 0, verbose = 0;
concise = (argc == 4 && (!strcasecmp(argv[3],"concise")));
verbose = (argc == 4 && (!strcasecmp(argv[3],"verbose")));
if (argc < 3 || argc > 4 || (argc == 4 && !concise && !verbose))
Mark Spencer
committed
return RESULT_SHOWUSAGE;
if (!concise && !verbose)
ast_cli(fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
else if (verbose)
ast_cli(fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
"CallerID", "Duration", "Accountcode", "BridgedTo");
Mark Spencer
committed
while ((c = ast_channel_walk_locked(c)) != NULL) {
struct ast_channel *bc = ast_bridged_channel(c);
Mark Spencer
committed
if ((concise || verbose) && c->cdr && !ast_tvzero(c->cdr->start)) {
duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
if (verbose) {
durh = duration / 3600;
durm = (duration % 3600) / 60;
durs = duration % 60;
snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
} else {
snprintf(durbuf, sizeof(durbuf), "%d", duration);
}
} else {
durbuf[0] = '\0';
}
if (concise) {
ast_cli(fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
c->appl ? c->appl : "(None)",
S_OR(c->data, ""), /* XXX different from verbose ? */
S_OR(c->cid.cid_num, ""),
S_OR(c->accountcode, ""),
c->amaflags,
durbuf,
bc ? bc->name : "(None)");
Mark Spencer
committed
} else if (verbose) {
ast_cli(fd, VERBOSE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
c->appl ? c->appl : "(None)",
c->data ? S_OR(c->data, "(Empty)" ): "(None)",
S_OR(c->cid.cid_num, ""),
durbuf,
S_OR(c->accountcode, ""),
bc ? bc->name : "(None)");
Mark Spencer
committed
} else {
if (!ast_strlen_zero(c->context) && !ast_strlen_zero(c->exten))
snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", c->exten, c->context, c->priority);
else
strcpy(locbuf, "(None)");
Mark Spencer
committed
snprintf(appdata, sizeof(appdata), "%s(%s)", c->appl, c->data ? c->data : "");
Mark Spencer
committed
strcpy(appdata, "(None)");
ast_cli(fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
}
ast_channel_unlock(c);
Mark Spencer
committed
if (!concise) {
ast_cli(fd, "%d active channel%s\n", numchans, ESS(numchans));
ast_cli(fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
ast_cli(fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
Mark Spencer
committed
#undef FORMAT_STRING
#undef FORMAT_STRING2
#undef CONCISE_FORMAT_STRING
#undef VERBOSE_FORMAT_STRING
#undef VERBOSE_FORMAT_STRING2
"Usage: core show channel <channel>\n"
" Shows lots of information about the specified channel.\n";
"Usage: core set debug channel <channel> [off]\n"
" Enables/disables debugging on a specific channel.\n";
static char commandcomplete_help[] =
"Usage: _command complete \"<line>\" text state\n"
" This function is used internally to help with command completion and should.\n"
" never be called by the user directly.\n";
static char commandnummatches_help[] =
"Usage: _command nummatches \"<line>\" text \n"
" This function is used internally to help with command completion and should.\n"
" never be called by the user directly.\n";
static char commandmatchesarray_help[] =
"Usage: _command matchesarray \"<line>\" text \n"
" This function is used internally to help with command completion and should.\n"
" never be called by the user directly.\n";
static int handle_softhangup(int fd, int argc, char *argv[])
{
struct ast_channel *c=NULL;
if (argc != 3)
return RESULT_SHOWUSAGE;
Kevin P. Fleming
committed
c = ast_get_channel_by_name_locked(argv[2]);
if (c) {
ast_cli(fd, "Requested Hangup on channel '%s'\n", c->name);
ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
ast_channel_unlock(c);
Kevin P. Fleming
committed
} else
ast_cli(fd, "%s is not a known channel\n", argv[2]);
return RESULT_SUCCESS;
}
Russell Bryant
committed
static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
static int handle_commandmatchesarray(int fd, int argc, char *argv[])
{
int buflen = 2048;
Russell Bryant
committed
if (!(buf = ast_malloc(buflen)))
return RESULT_FAILURE;
buf[len] = '\0';
matches = ast_cli_completion_matches(argv[2], argv[3]);
if (matches) {
for (x=0; matches[x]; x++) {
matchlen = strlen(matches[x]) + 1;
if (len + matchlen >= buflen) {
buflen += matchlen * 3;
obuf = buf;
Russell Bryant
committed
if (!(buf = ast_realloc(obuf, buflen)))
/* Memory allocation failure... Just free old buffer and be done */
}
if (buf)
len += sprintf( buf + len, "%s ", matches[x]);
free(matches[x]);
matches[x] = NULL;
ast_cli(fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
free(buf);
} else
ast_cli(fd, "NULL\n");
return RESULT_SUCCESS;
}
static int handle_commandnummatches(int fd, int argc, char *argv[])
{
int matches = 0;
if (argc != 4)
return RESULT_SHOWUSAGE;
matches = ast_cli_generatornummatches(argv[2], argv[3]);
ast_cli(fd, "%d", matches);
return RESULT_SUCCESS;
}
static int handle_commandcomplete(int fd, int argc, char *argv[])
{
char *buf;
if (argc != 5)
return RESULT_SHOWUSAGE;
buf = __ast_cli_generator(argv[2], argv[3], atoi(argv[4]), 0);
if (buf) {
ast_cli(fd, buf);
free(buf);
} else
ast_cli(fd, "NULL\n");
return RESULT_SUCCESS;
}
static int handle_debugchan_deprecated(int fd, int argc, char *argv[])
Mark Spencer
committed
int is_all;
/* 'debug channel {all|chan_id}' */
Mark Spencer
committed
is_all = !strcasecmp("all", argv[3]);
Mark Spencer
committed
if (is_all) {
Kevin P. Fleming
committed
global_fin |= DEBUGCHAN_FLAG;
global_fout |= DEBUGCHAN_FLAG;
c = ast_channel_walk_locked(NULL);
} else {
c = ast_get_channel_by_name_locked(argv[3]);
Kevin P. Fleming
committed
if (c == NULL)
ast_cli(fd, "No such channel %s\n", argv[3]);
Mark Spencer
committed
}
while (c) {
Kevin P. Fleming
committed
if (!(c->fin & DEBUGCHAN_FLAG) || !(c->fout & DEBUGCHAN_FLAG)) {
c->fin |= DEBUGCHAN_FLAG;
c->fout |= DEBUGCHAN_FLAG;
ast_cli(fd, "Debugging enabled on channel %s\n", c->name);
ast_channel_unlock(c);
Kevin P. Fleming
committed
if (!is_all)
break;
c = ast_channel_walk_locked(c);
Kevin P. Fleming
committed
ast_cli(fd, "Debugging on new channels is enabled\n");
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
static int handle_core_set_debug_channel(int fd, int argc, char *argv[])
{
struct ast_channel *c = NULL;
int is_all, is_off = 0;
/* 'core set debug channel {all|chan_id}' */
if (argc == 6 && strcmp(argv[5], "off") == 0)
is_off = 1;
else if (argc != 5)
return RESULT_SHOWUSAGE;
is_all = !strcasecmp("all", argv[4]);
if (is_all) {
if (is_off) {
global_fin &= ~DEBUGCHAN_FLAG;
global_fout &= ~DEBUGCHAN_FLAG;
} else {
global_fin |= DEBUGCHAN_FLAG;
global_fout |= DEBUGCHAN_FLAG;
}
c = ast_channel_walk_locked(NULL);
} else {
c = ast_get_channel_by_name_locked(argv[4]);
if (c == NULL)
ast_cli(fd, "No such channel %s\n", argv[4]);
}
while (c) {
if (!(c->fin & DEBUGCHAN_FLAG) || !(c->fout & DEBUGCHAN_FLAG)) {
if (is_off) {
c->fin &= ~DEBUGCHAN_FLAG;
c->fout &= ~DEBUGCHAN_FLAG;
} else {
c->fin |= DEBUGCHAN_FLAG;
c->fout |= DEBUGCHAN_FLAG;
}
ast_cli(fd, "Debugging %s on channel %s\n", is_off ? "disabled" : "enabled", c->name);
}
ast_channel_unlock(c);
if (!is_all)
break;
c = ast_channel_walk_locked(c);
}
ast_cli(fd, "Debugging on new channels is %s\n", is_off ? "disabled" : "enabled");
return RESULT_SUCCESS;
}
static int handle_nodebugchan_deprecated(int fd, int argc, char *argv[])
{
struct ast_channel *c=NULL;
int is_all;
/* 'no debug channel {all|chan_id}' */
is_all = !strcasecmp("all", argv[3]);
if (is_all) {
global_fin &= ~DEBUGCHAN_FLAG;
global_fout &= ~DEBUGCHAN_FLAG;
c = ast_channel_walk_locked(NULL);
} else {
c = ast_get_channel_by_name_locked(argv[3]);
ast_cli(fd, "No such channel %s\n", argv[3]);
}
while(c) {
if ((c->fin & DEBUGCHAN_FLAG) || (c->fout & DEBUGCHAN_FLAG)) {
c->fin &= ~DEBUGCHAN_FLAG;
c->fout &= ~DEBUGCHAN_FLAG;
ast_cli(fd, "Debugging disabled on channel %s\n", c->name);
}
ast_channel_unlock(c);
if (!is_all)
break;
c = ast_channel_walk_locked(c);
}
ast_cli(fd, "Debugging on new channels is disabled\n");
return RESULT_SUCCESS;
}
static int handle_showchan(int fd, int argc, char *argv[])
{
struct ast_channel *c=NULL;
Mark Spencer
committed
char cdrtime[256];
char nf[256], wf[256], rf[256];
int hour=0, min=0, sec=0;
Kevin P. Fleming
committed
now = ast_tvnow();
c = ast_get_channel_by_name_locked(argv[3]);
Kevin P. Fleming
committed
if (!c) {
ast_cli(fd, "%s is not a known channel\n", argv[3]);
Kevin P. Fleming
committed
return RESULT_SUCCESS;
}
if(c->cdr) {
elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
hour = elapsed_seconds / 3600;
min = (elapsed_seconds % 3600) / 60;
sec = elapsed_seconds % 60;
snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
} else
Kevin P. Fleming
committed
ast_cli(fd,
" -- General --\n"
" Name: %s\n"
" Type: %s\n"
" UniqueID: %s\n"
" Caller ID: %s\n"
" Caller ID Name: %s\n"
" DNID Digits: %s\n"
" State: %s (%d)\n"
" Rings: %d\n"
" NativeFormats: %s\n"
" WriteFormat: %s\n"
" ReadFormat: %s\n"
" WriteTranscode: %s\n"
" ReadTranscode: %s\n"
Kevin P. Fleming
committed
"1st File Descriptor: %d\n"
" Frames in: %d%s\n"
" Frames out: %d%s\n"
" Time to Hangup: %ld\n"
" Elapsed Time: %s\n"
" Direct Bridge: %s\n"
"Indirect Bridge: %s\n"
" -- PBX --\n"
" Context: %s\n"
" Extension: %s\n"
" Priority: %d\n"
" Call Group: %llu\n"
" Pickup Group: %llu\n"
Kevin P. Fleming
committed
" Application: %s\n"
" Data: %s\n"
" Blocking in: %s\n",
c->name, c->tech->type, c->uniqueid,
S_OR(c->cid.cid_num, "(N/A)"),
S_OR(c->cid.cid_name, "(N/A)"),
S_OR(c->cid.cid_dnid, "(N/A)"), ast_state2str(c->_state), c->_state, c->rings,
ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
ast_getformatname_multiple(wf, sizeof(wf), c->writeformat),
ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
c->writetrans ? "Yes" : "No",
c->readtrans ? "Yes" : "No",
c->fds[0],
c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
(long)c->whentohangup,
Kevin P. Fleming
committed
cdrtime, c->_bridge ? c->_bridge->name : "<none>", ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ),
( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
Kevin P. Fleming
committed
(ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
if(pbx_builtin_serialize_variables(c,buf,sizeof(buf)))
ast_cli(fd," Variables:\n%s\n",buf);
if(c->cdr && ast_cdr_serialize_variables(c->cdr,buf, sizeof(buf), '=', '\n', 1))
ast_cli(fd," CDR Variables:\n%s\n",buf);
ast_channel_unlock(c);
/*
* helper function to generate CLI matches from a fixed set of values.
* A NULL word is acceptable.
*/
char *ast_cli_complete(const char *word, char *const choices[], int state)
Mark Spencer
committed
{
int i, which = 0, len;
len = ast_strlen_zero(word) ? 0 : strlen(word);
for (i = 0; choices[i]; i++) {
if ((!len || !strncasecmp(word, choices[i], len)) && ++which > state)
return ast_strdup(choices[i]);
Mark Spencer
committed
}
return NULL;
}
static char *complete_show_channels(const char *line, const char *word, int pos, int state)
{
static char *choices[] = { "concise", "verbose", NULL };
return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Kevin P. Fleming
committed
struct ast_channel *c = NULL;
int which = 0;
int wordlen;
char notfound = '\0';
char *ret = ¬found; /* so NULL can break the loop */
Kevin P. Fleming
committed
if (pos != rpos)
return NULL;
wordlen = strlen(word);
while (ret == ¬found && (c = ast_channel_walk_locked(c))) {
if (!strncasecmp(word, c->name, wordlen) && ++which > state)
ret = ast_strdup(c->name);
ast_channel_unlock(c);
return ret == ¬found ? NULL : ret;
Russell Bryant
committed
static char *complete_ch_3(const char *line, const char *word, int pos, int state)
return ast_complete_channels(line, word, pos, state, 2);
static char *complete_ch_4(const char *line, const char *word, int pos, int state)
{
return ast_complete_channels(line, word, pos, state, 3);
}
static char *complete_ch_5(const char *line, const char *word, int pos, int state)
{
return ast_complete_channels(line, word, pos, state, 4);
}
static char *complete_mod_2(const char *line, const char *word, int pos, int state)
{
return ast_module_helper(line, word, pos, state, 1, 1);
}
static char *complete_mod_3_nr(const char *line, const char *word, int pos, int state)
{
return ast_module_helper(line, word, pos, state, 2, 0);
}
static char *complete_mod_3(const char *line, const char *word, int pos, int state)
{
if (pos < 2)
return NULL;
return ast_module_helper(line, word, pos, state, pos, 1);
}
static char *complete_fn(const char *line, const char *word, int pos, int state)
{
char *c;
char filename[256];
return NULL;
if (word[0] == '/')
ast_copy_string(filename, word, sizeof(filename));
else
snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
c = filename_completion_function(filename, state);
if (c && word[0] != '/')
c += (strlen(ast_config_AST_MODULE_DIR) + 1);
return c ? strdup(c) : c;
}
Russell Bryant
committed
static int group_show_channels(int fd, int argc, char *argv[])
{
#define FORMAT_STRING "%-25s %-20s %-20s\n"