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 "asterisk/_private.h"
#include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
#include <sys/signal.h>
#include <signal.h>
#include <ctype.h>
Russell Bryant
committed
#include <regex.h>
Kevin P. Fleming
committed
#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"
/*!
* \brief map a debug or verbose value to a filename
*/
struct ast_debug_file {
unsigned int level;
AST_RWLIST_ENTRY(ast_debug_file) entry;
char filename[0];
};
AST_RWLIST_HEAD(debug_file_list, ast_debug_file);
/*! list of filenames and their debug settings */
static struct debug_file_list debug_files;
/*! list of filenames and their verbose settings */
static struct debug_file_list verbose_files;
Russell Bryant
committed
AST_THREADSTORAGE(ast_cli_buf);
/*! \brief Initial buffer size for resulting strings in ast_cli() */
#define AST_CLI_INITLEN 256
void ast_cli(int fd, const char *fmt, ...)
Russell Bryant
committed
int res;
if (!(buf = ast_str_thread_get(&ast_cli_buf, AST_CLI_INITLEN)))
res = ast_str_set_va(&buf, 0, fmt, ap);
if (res != AST_DYNSTR_BUILD_FAILED)
ast_carefulwrite(fd, buf->str, strlen(buf->str), 100);
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
unsigned int ast_debug_get_by_file(const char *file)
{
struct ast_debug_file *adf;
unsigned int res = 0;
AST_RWLIST_RDLOCK(&debug_files);
AST_LIST_TRAVERSE(&debug_files, adf, entry) {
if (!strncasecmp(adf->filename, file, strlen(adf->filename))) {
res = adf->level;
break;
}
}
AST_RWLIST_UNLOCK(&debug_files);
return res;
}
unsigned int ast_verbose_get_by_file(const char *file)
{
struct ast_debug_file *adf;
unsigned int res = 0;
AST_RWLIST_RDLOCK(&verbose_files);
AST_LIST_TRAVERSE(&verbose_files, adf, entry) {
if (!strncasecmp(adf->filename, file, strlen(file))) {
res = adf->level;
break;
}
}
AST_RWLIST_UNLOCK(&verbose_files);
return res;
}
static AST_RWLIST_HEAD_STATIC(helpers, ast_cli_entry);
static char *complete_fn(const char *word, int state)
{
char filename[256];
if (word[0] == '/')
ast_copy_string(filename, word, sizeof(filename));
else
snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
c = d = filename_completion_function(filename, state);
if (c && word[0] != '/')
c += (strlen(ast_config_AST_MODULE_DIR) + 1);
if (c)
c = ast_strdup(c);
if (d)
free(d);
}
static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
/* "module load <mod>" */
switch (cmd) {
case CLI_INIT:
e->command = "module load";
e->usage =
"Usage: module load <module name>\n"
" Loads the specified module into Asterisk.\n";
return NULL;
case CLI_GENERATE:
if (a->pos != e->args)
return NULL;
return complete_fn(a->word, a->n);
if (a->argc != e->args + 1)
return CLI_SHOWUSAGE;
if (ast_load_resource(a->argv[e->args])) {
ast_cli(a->fd, "Unable to load module %s\n", a->argv[e->args]);
return CLI_FAILURE;
}
return CLI_SUCCESS;
static char *handle_load_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
char *res = handle_load(e, cmd, a);
if (cmd == CLI_INIT)
e->command = "load";
return res;
static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
switch (cmd) {
case CLI_INIT:
e->command = "module reload";
e->usage =
"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";
return NULL;
case CLI_GENERATE:
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 1);
}
if (a->argc == e->args) {
ast_module_reload(NULL);
return CLI_SUCCESS;
}
for (x = e->args; x < a->argc; x++) {
int res = ast_module_reload(a->argv[x]);
/* XXX reload has multiple error returns, including -1 on error and 2 on success */
Joshua Colp
committed
switch (res) {
case 0:
ast_cli(a->fd, "No such module '%s'\n", a->argv[x]);
break;
case 1:
ast_cli(a->fd, "Module '%s' does not support reload\n", a->argv[x]);
break;
static char *handle_reload_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
char *s = handle_reload(e, cmd, a);
if (cmd == CLI_INIT) /* override command name */
e->command = "reload";
return s;
/*!
* \brief Find the debug or verbose file setting
* \arg debug 1 for debug, 0 for verbose
*/
static struct ast_debug_file *find_debug_file(const char *fn, unsigned int debug)
{
struct ast_debug_file *df = NULL;
struct debug_file_list *dfl = debug ? &debug_files : &verbose_files;
AST_LIST_TRAVERSE(dfl, df, entry) {
if (!strcasecmp(df->filename, fn))
break;
}
return df;
}
static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Mark Michelson
committed
int oldval;
int newlevel;
int atleast = 0;
int fd = a->fd;
int argc = a->argc;
char **argv = a->argv;
int *dst;
char *what;
struct debug_file_list *dfl;
struct ast_debug_file *adf;
char *fn;
switch (cmd) {
case CLI_INIT:
e->command = "core set {debug|verbose} [off|atleast]";
"Usage: core set {debug|verbose} [atleast] <level> [filename]\n"
" core set {debug|verbose} off\n"
" Sets level of debug or verbose messages to be displayed or \n"
" sets a filename to display debug messages from.\n"
" 0 or off means no messages should be displayed.\n"
" Equivalent to -d[d[...]] or -v[v[v...]] on startup\n";
case CLI_GENERATE:
}
/* all the above return, so we proceed with the handler.
* we are guaranteed to be called with argc >= e->args;
*/
if (argc < e->args)
return CLI_SHOWUSAGE;
if (!strcasecmp(argv[e->args - 2], "debug")) {
dst = &option_debug;
Mark Michelson
committed
oldval = option_debug;
what = "Core debug";
} else {
dst = &option_verbose;
Mark Michelson
committed
oldval = option_verbose;
what = "Verbosity";
}
if (argc == e->args && !strcasecmp(argv[e->args - 1], "off")) {
newlevel = 0;
dfl = debug ? &debug_files : &verbose_files;
AST_RWLIST_WRLOCK(dfl);
while ((adf = AST_RWLIST_REMOVE_HEAD(dfl, entry)))
ast_free(adf);
ast_clear_flag(&ast_options, debug ? AST_OPT_FLAG_DEBUG_FILE : AST_OPT_FLAG_VERBOSE_FILE);
AST_RWLIST_UNLOCK(dfl);
goto done;
}
if (!strcasecmp(argv[e->args-1], "atleast"))
atleast = 1;
if (argc != e->args + atleast && argc != e->args + atleast + 1)
return CLI_SHOWUSAGE;
if (sscanf(argv[e->args + atleast - 1], "%d", &newlevel) != 1)
return CLI_SHOWUSAGE;
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
if (argc == e->args + atleast + 1) {
unsigned int debug = (*what == 'C');
dfl = debug ? &debug_files : &verbose_files;
fn = argv[e->args + atleast];
AST_RWLIST_WRLOCK(dfl);
if ((adf = find_debug_file(fn, debug)) && !newlevel) {
AST_RWLIST_REMOVE(dfl, adf, entry);
if (AST_RWLIST_EMPTY(dfl))
ast_clear_flag(&ast_options, debug ? AST_OPT_FLAG_DEBUG_FILE : AST_OPT_FLAG_VERBOSE_FILE);
AST_RWLIST_UNLOCK(dfl);
ast_cli(fd, "%s was %d and has been set to 0 for '%s'\n", what, adf->level, fn);
ast_free(adf);
return CLI_SUCCESS;
}
if (adf) {
if ((atleast && newlevel < adf->level) || adf->level == newlevel) {
ast_cli(fd, "%s is %d for '%s'\n", what, adf->level, fn);
AST_RWLIST_UNLOCK(dfl);
return CLI_SUCCESS;
}
} else if (!(adf = ast_calloc(1, sizeof(*adf) + strlen(fn) + 1))) {
AST_RWLIST_UNLOCK(dfl);
return CLI_FAILURE;
}
oldval = adf->level;
adf->level = newlevel;
strcpy(adf->filename, fn);
ast_set_flag(&ast_options, debug ? AST_OPT_FLAG_DEBUG_FILE : AST_OPT_FLAG_VERBOSE_FILE);
AST_RWLIST_INSERT_TAIL(dfl, adf, entry);
AST_RWLIST_UNLOCK(dfl);
ast_cli(fd, "%s was %d and has been set to %d for '%s'\n", what, oldval, adf->level, adf->filename);
return CLI_SUCCESS;
}
if (!atleast || newlevel > *dst)
*dst = newlevel;
if (oldval > 0 && *dst == 0)
ast_cli(fd, "%s is now OFF\n", what);
else if (*dst > 0) {
if (oldval == *dst)
ast_cli(fd, "%s is at least %d\n", what, *dst);
ast_cli(fd, "%s was %d and is now %d\n", what, oldval, *dst);
return CLI_SUCCESS;
static char *handle_logger_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Joshua Colp
committed
{
switch (cmd) {
case CLI_INIT:
e->command = "logger mute";
e->usage =
"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";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc < 2 || a->argc > 3)
return CLI_SHOWUSAGE;
if (a->argc == 3 && !strcasecmp(a->argv[2], "silent"))
ast_console_toggle_mute(a->fd, 1);
else
ast_console_toggle_mute(a->fd, 0);
return CLI_SUCCESS;
Joshua Colp
committed
}
static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
/* "module unload mod_1 [mod_2 .. mod_N]" */
int x;
int force = AST_FORCE_SOFT;
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
char *s;
switch (cmd) {
case CLI_INIT:
e->command = "module unload";
e->usage =
"Usage: module unload [-f|-h] <module_1> [<module_2> ... ]\n"
" 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";
return NULL;
case CLI_GENERATE:
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
}
if (a->argc < e->args + 1)
return CLI_SHOWUSAGE;
x = e->args; /* first argument */
s = a->argv[x];
if (s[0] == '-') {
if (s[1] == 'f')
force = AST_FORCE_FIRM;
else if (s[1] == 'h')
force = AST_FORCE_HARD;
else
return CLI_SHOWUSAGE;
if (a->argc < e->args + 2) /* need at least one module name */
return CLI_SHOWUSAGE;
x++; /* skip this argument */
}
for (; x < a->argc; x++) {
if (ast_unload_resource(a->argv[x], force)) {
ast_cli(a->fd, "Unable to unload resource %s\n", a->argv[x]);
return CLI_FAILURE;
static char *handle_unload_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
char *res = handle_unload(e, cmd, a);
if (cmd == CLI_INIT)
e->command = "unload"; /* XXX override */
return res;
#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);
Tilghman Lesher
committed
static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
int x; /* the main part - years, weeks, etc. */
Mark Spencer
committed
#define MINUTE (SECOND*60)
#define HOUR (MINUTE*60)
#define DAY (HOUR*24)
#define WEEK (DAY*7)
#define YEAR (DAY*365)
#define NEEDCOMMA(x) ((x)? ",": "") /* define if we need a comma */
Tilghman Lesher
committed
if (timeval.tv_sec < 0) /* invalid, nothing to show */
if (printsec) { /* plain seconds output */
Tilghman Lesher
committed
ast_cli(fd, "%s: %lu\n", prefix, (u_long)timeval.tv_sec);
out = ast_str_alloca(256);
Tilghman Lesher
committed
if (timeval.tv_sec > YEAR) {
x = (timeval.tv_sec / YEAR);
timeval.tv_sec -= (x * YEAR);
ast_str_append(&out, 0, "%d year%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
Tilghman Lesher
committed
if (timeval.tv_sec > WEEK) {
x = (timeval.tv_sec / WEEK);
timeval.tv_sec -= (x * WEEK);
ast_str_append(&out, 0, "%d week%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
Tilghman Lesher
committed
if (timeval.tv_sec > DAY) {
x = (timeval.tv_sec / DAY);
timeval.tv_sec -= (x * DAY);
ast_str_append(&out, 0, "%d day%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
Tilghman Lesher
committed
if (timeval.tv_sec > HOUR) {
x = (timeval.tv_sec / HOUR);
timeval.tv_sec -= (x * HOUR);
ast_str_append(&out, 0, "%d hour%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
Tilghman Lesher
committed
if (timeval.tv_sec > MINUTE) {
x = (timeval.tv_sec / MINUTE);
timeval.tv_sec -= (x * MINUTE);
ast_str_append(&out, 0, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
Tilghman Lesher
committed
x = timeval.tv_sec;
if (x > 0 || out->used == 0) /* if there is nothing, print 0 seconds */
ast_str_append(&out, 0, "%d second%s ", x, ESS(x));
ast_cli(fd, "%s: %s\n", prefix, out->str);
static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Tilghman Lesher
committed
struct timeval curtime = ast_tvnow();
Luigi Rizzo
committed
int printsec;
e->command = "core show uptime [seconds]";
Luigi Rizzo
committed
"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:
return NULL;
Luigi Rizzo
committed
}
/* regular handler */
if (a->argc == e->args && !strcasecmp(a->argv[e->args-1],"seconds"))
Luigi Rizzo
committed
printsec = 1;
else if (a->argc == e->args-1)
Luigi Rizzo
committed
printsec = 0;
else
return CLI_SHOWUSAGE;
Tilghman Lesher
committed
if (ast_startuptime.tv_sec)
print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec);
if (ast_lastreloadtime.tv_sec)
print_uptimestr(a->fd, ast_tvsub(curtime, ast_lastreloadtime), "Last reload", printsec);
return CLI_SUCCESS;
static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
switch (cmd) {
case CLI_INIT:
"Usage: module show [like keyword]\n"
" Shows Asterisk modules currently in use, and usage statistics.\n";
case CLI_GENERATE:
if (a->pos == e->args)
return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
/* all the above return, so we proceed with the handler.
* we are guaranteed to have argc >= e->args
*/
else if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args-1], "like") )
like = a->argv[e->args];
return CLI_SHOWUSAGE;
ast_mutex_lock(&climodentrylock);
climodentryfd = a->fd; /* global, protected by climodentrylock */
ast_cli(a->fd, MODLIST_FORMAT2, "Module", "Description", "Use Count");
ast_cli(a->fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
ast_mutex_unlock(&climodentrylock);
return CLI_SUCCESS;
Mark Spencer
committed
#undef MODLIST_FORMAT
#undef MODLIST_FORMAT2
Jason Parker
committed
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct timeval curtime = ast_tvnow();
int showuptime, printsec;
switch (cmd) {
case CLI_INIT:
e->command = "core show calls [uptime]";
e->usage =
"Usage: core show calls [uptime] [seconds]\n"
" Lists number of currently active calls and total number of calls\n"
" processed through PBX since last restart. If 'uptime' is specified\n"
" the system uptime is also displayed. If 'seconds' is specified in\n"
" addition to 'uptime', the system uptime is displayed in seconds.\n";
return NULL;
case CLI_GENERATE:
if (a->pos != e->args)
return NULL;
return a->n == 0 ? ast_strdup("seconds") : NULL;
}
/* regular handler */
if (a->argc >= e->args && !strcasecmp(a->argv[e->args-1],"uptime")) {
showuptime = 1;
if (a->argc == e->args+1 && !strcasecmp(a->argv[e->args],"seconds"))
printsec = 1;
else if (a->argc == e->args)
printsec = 0;
else
return CLI_SHOWUSAGE;
} else if (a->argc == e->args-1) {
showuptime = 0;
printsec = 0;
} else
return CLI_SHOWUSAGE;
if (option_maxcalls) {
ast_cli(a->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);
} else {
ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
}
ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
if (ast_startuptime.tv_sec && showuptime) {
print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec);
}
return RESULT_SUCCESS;
}
static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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"
#define CONCISE_FORMAT_STRING "%s!%s!%s!%d!%s!%s!%s!%s!%s!%d!%s!%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;
Joshua Colp
committed
int numchans = 0, concise = 0, verbose = 0, count = 0;
Joshua Colp
committed
e->command = "core show channels [concise|verbose|count]";
Joshua Colp
committed
"Usage: core show channels [concise|verbose|count]\n"
" 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"
Joshua Colp
committed
" more and longer fields. If 'count' is specified only the channel and call\n"
" count is output.\n"
" The 'concise' option is deprecated and will be removed from future versions\n"
" of Asterisk.\n";
case CLI_GENERATE:
return NULL;
}
fd = a->fd;
argc = a->argc;
argv = a->argv;
if (a->argc == e->args) {
if (!strcasecmp(argv[e->args-1],"concise"))
else if (!strcasecmp(argv[e->args-1],"verbose"))
Joshua Colp
committed
else if (!strcasecmp(argv[e->args-1],"count"))
count = 1;
} else if (a->argc != e->args - 1)
Mark Spencer
committed
Joshua Colp
committed
if (!count) {
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);
char durbuf[10] = "-";
Joshua Colp
committed
if (!count) {
if ((concise || verbose) && c->cdr && !ast_tvzero(c->cdr->start)) {
int duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
if (verbose) {
int durh = duration / 3600;
int durm = (duration % 3600) / 60;
int durs = duration % 60;
snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
} else {
snprintf(durbuf, sizeof(durbuf), "%d", duration);
}
}
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)",
c->uniqueid);
Joshua Colp
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 {
Joshua Colp
committed
char locbuf[40] = "(None)";
char appdata[40] = "(None)";
if (!ast_strlen_zero(c->context) && !ast_strlen_zero(c->exten))
snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", c->exten, c->context, c->priority);
if (c->appl)
snprintf(appdata, sizeof(appdata), "%s(%s)", c->appl, S_OR(c->data, ""));
Joshua Colp
committed
ast_cli(fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
}
Mark Spencer
committed
}
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()));
Jason Parker
committed
ast_cli(fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
Mark Spencer
committed
#undef FORMAT_STRING
#undef FORMAT_STRING2
#undef CONCISE_FORMAT_STRING
#undef VERBOSE_FORMAT_STRING
#undef VERBOSE_FORMAT_STRING2
static char *handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
switch (cmd) {
case CLI_INIT:
e->command = "soft hangup";
e->usage =
"Usage: soft hangup <channel>\n"
" Request that a channel be hung up. The hangup takes effect\n"
" the next time the driver reads or writes from the channel\n";
return NULL;
case CLI_GENERATE:
return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
}
if (a->argc != 3)
return CLI_SHOWUSAGE;
c = ast_get_channel_by_name_locked(a->argv[2]);
Kevin P. Fleming
committed
if (c) {
ast_cli(a->fd, "Requested Hangup on channel '%s'\n", c->name);
Kevin P. Fleming
committed
ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
ast_channel_unlock(c);
Kevin P. Fleming
committed
} else
ast_cli(a->fd, "%s is not a known channel\n", a->argv[2]);
return CLI_SUCCESS;
Russell Bryant
committed
static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
static char *handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
int buflen = 2048;
switch (cmd) {
case CLI_INIT:
e->command = "_command matchesarray";
e->usage =
"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";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 4)
return CLI_SHOWUSAGE;
Russell Bryant
committed
if (!(buf = ast_malloc(buflen)))
return CLI_FAILURE;
matches = ast_cli_completion_matches(a->argv[2], a->argv[3]);
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 */
Tilghman Lesher
committed
ast_free(obuf);
}
if (buf)
len += sprintf( buf + len, "%s ", matches[x]);
Tilghman Lesher
committed
ast_free(matches[x]);
Tilghman Lesher
committed
ast_free(matches);
ast_cli(a->fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
Tilghman Lesher
committed
ast_free(buf);
ast_cli(a->fd, "NULL\n");
return CLI_SUCCESS;
static char *handle_commandnummatches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
switch (cmd) {
case CLI_INIT:
e->command = "_command nummatches";
e->usage =
"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";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 4)
return CLI_SHOWUSAGE;
matches = ast_cli_generatornummatches(a->argv[2], a->argv[3]);
ast_cli(a->fd, "%d", matches);
return CLI_SUCCESS;
static char *handle_commandcomplete(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
switch (cmd) {
case CLI_INIT:
e->command = "_command complete";
e->usage =
"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";
return NULL;
case CLI_GENERATE:
return NULL;
}
if (a->argc != 5)
return CLI_SHOWUSAGE;
buf = __ast_cli_generator(a->argv[2], a->argv[3], atoi(a->argv[4]), 0);
ast_cli(a->fd, "%s", buf);
Tilghman Lesher
committed
ast_free(buf);
ast_cli(a->fd, "NULL\n");
return CLI_SUCCESS;
static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_channel *c = NULL;
int is_all, is_off = 0;
switch (cmd) {
case CLI_INIT:
e->command = "core set debug channel";
e->usage =
"Usage: core set debug channel <all|channel> [off]\n"
" Enables/disables debugging on all or on a specific channel.\n";
return NULL;
case CLI_GENERATE:
/* XXX remember to handle the optional "off" */
if (a->pos != e->args)
return NULL;
return a->n == 0 ? ast_strdup("all") : ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args);
/* 'core set debug channel {all|chan_id}' */
if (a->argc == e->args + 2) {
if (!strcasecmp(a->argv[e->args + 1], "off"))
is_off = 1;
else
return CLI_SHOWUSAGE;
} else if (a->argc != e->args + 1)
return CLI_SHOWUSAGE;
is_all = !strcasecmp("all", a->argv[e->args]);
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(a->argv[e->args]);
ast_cli(a->fd, "No such channel %s\n", a->argv[e->args]);
}
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(a->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(a->fd, "Debugging on new channels is %s\n", is_off ? "disabled" : "enabled");
return CLI_SUCCESS;
static char *handle_debugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
char *res;
if (cmd == CLI_HANDLER && a->argc != e->args + 1)
return CLI_SHOWUSAGE;
res = handle_core_set_debug_channel(e, cmd, a);
if (cmd == CLI_INIT)
e->command = "debug channel";
return res;
}
static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
char *res;
if (cmd == CLI_HANDLER) {
if (a->argc != e->args + 1)
return CLI_SHOWUSAGE;
/* pretend we have an extra "off" at the end. We can do this as the array
* is NULL terminated so we overwrite that entry.
*/
a->argv[e->args+1] = "off";
a->argc++;
res = handle_core_set_debug_channel(e, cmd, a);
if (cmd == CLI_INIT)
e->command = "no debug channel";
return res;
static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
struct ast_str *out = ast_str_alloca(2048);
Mark Spencer
committed
char cdrtime[256];
char nf[256], wf[256], rf[256];
int hour=0, min=0, sec=0;
#ifdef CHANNEL_TRACE
int trace_enabled;
#endif
switch (cmd) {
case CLI_INIT:
e->command = "core show channel";
e->usage =
"Usage: core show channel <channel>\n"
" Shows lots of information about the specified channel.\n";
return NULL;