00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
#include <unistd.h>
00015
#include <stdlib.h>
00016
#include <asterisk/logger.h>
00017
#include <asterisk/options.h>
00018
#include <asterisk/cli.h>
00019
#include <asterisk/module.h>
00020
#include <asterisk/channel.h>
00021
#include <asterisk/channel_pvt.h>
00022
#include <asterisk/manager.h>
00023
#include <asterisk/utils.h>
00024
#include <asterisk/lock.h>
00025
#include <sys/signal.h>
00026
#include <stdio.h>
00027
#include <signal.h>
00028
#include <string.h>
00029
00030
#include "readline/readline.h"
00031
00032
#include "asterisk.h"
00033
#include "build.h"
00034
#include "astconf.h"
00035
00036 #define VERSION_INFO "Asterisk " ASTERISK_VERSION " built by " BUILD_USER "@" BUILD_HOSTNAME \
" on a " BUILD_MACHINE " running " BUILD_OS
00037
00038
void ast_cli(
int fd,
char *fmt, ...)
00039 {
00040
char *stuff;
00041
int res = 0;
00042
00043 va_list ap;
00044 va_start(ap, fmt);
00045 res =
vasprintf(&stuff, fmt, ap);
00046 va_end(ap);
00047
if (res == -1) {
00048
ast_log(
LOG_ERROR,
"Out of memory\n");
00049 }
else {
00050
ast_carefulwrite(fd, stuff, strlen(stuff), 100);
00051
free(stuff);
00052 }
00053 }
00054
00055
AST_MUTEX_DEFINE_STATIC(clilock);
00056
00057
struct ast_cli_entry *
helpers = NULL;
00058
00059
static char load_help[] =
00060
"Usage: load <module name>\n"
00061
" Loads the specified module into Asterisk.\n";
00062
00063
static char unload_help[] =
00064
"Usage: unload [-f|-h] <module name>\n"
00065
" Unloads the specified module from Asterisk. The -f\n"
00066
" option causes the module to be unloaded even if it is\n"
00067
" in use (may cause a crash) and the -h module causes the\n"
00068
" module to be unloaded even if the module says it cannot, \n"
00069
" which almost always will cause a crash.\n";
00070
00071
static char help_help[] =
00072
"Usage: help [topic]\n"
00073
" When called with a topic as an argument, displays usage\n"
00074
" information on the given command. If called without a\n"
00075
" topic, it provides a list of commands.\n";
00076
00077
static char chanlist_help[] =
00078
"Usage: show channels [concise]\n"
00079
" Lists currently defined channels and some information about\n"
00080
" them. If 'concise' is specified, format is abridged and in\n"
00081
" a more easily machine parsable format\n";
00082
00083
static char reload_help[] =
00084
"Usage: reload [module ...]\n"
00085
" Reloads configuration files for all listed modules which support\n"
00086
" reloading, or for all supported modules if none are listed.\n";
00087
00088
static char set_verbose_help[] =
00089
"Usage: set verbose <level>\n"
00090
" Sets level of verbose messages to be displayed. 0 means\n"
00091
" no messages should be displayed. Equivalent to -v[v[v...]]\n"
00092
" on startup\n";
00093
00094
static char set_debug_help[] =
00095
"Usage: set debug <level>\n"
00096
" Sets level of core debug messages to be displayed. 0 means\n"
00097
" no messages should be displayed. Equivalent to -d[d[d...]]\n"
00098
" on startup.\n";
00099
00100
static char softhangup_help[] =
00101
"Usage: soft hangup <channel>\n"
00102
" Request that a channel be hung up. The hangup takes effect\n"
00103
" the next time the driver reads or writes from the channel\n";
00104
00105
static int handle_load(
int fd,
int argc,
char *argv[])
00106 {
00107
if (argc != 2)
00108
return RESULT_SHOWUSAGE;
00109
if (
ast_load_resource(argv[1])) {
00110
ast_cli(fd,
"Unable to load module %s\n", argv[1]);
00111
return RESULT_FAILURE;
00112 }
00113
return RESULT_SUCCESS;
00114 }
00115
00116
static int handle_reload(
int fd,
int argc,
char *argv[])
00117 {
00118
int x;
00119
if (argc < 1)
00120
return RESULT_SHOWUSAGE;
00121
if (argc > 1) {
00122
for (x=1;x<argc;x++)
00123
ast_module_reload(argv[x]);
00124 }
else
00125
ast_module_reload(NULL);
00126
return RESULT_SUCCESS;
00127 }
00128
00129
static int handle_set_verbose(
int fd,
int argc,
char *argv[])
00130 {
00131
int val = 0;
00132
int oldval = 0;
00133
00134
if ((argc != 3) && (argc != 4))
00135
return RESULT_SHOWUSAGE;
00136
if ((argc == 4) && strcasecmp(argv[2],
"atleast"))
00137
return RESULT_SHOWUSAGE;
00138 oldval =
option_verbose;
00139
if (argc == 3)
00140
option_verbose = atoi(argv[2]);
00141
else {
00142 val = atoi(argv[3]);
00143
if (val >
option_verbose)
00144
option_verbose = val;
00145 }
00146
if (oldval !=
option_verbose &&
option_verbose > 0)
00147
ast_cli(fd,
"Verbosity was %d and is now %d\n", oldval, option_verbose);
00148
else if (oldval > 0 &&
option_verbose > 0)
00149
ast_cli(fd,
"Verbosity is atleast %d\n", option_verbose);
00150
else if (oldval > 0 &&
option_debug == 0)
00151
ast_cli(fd,
"Verbosity is now OFF\n");
00152
return RESULT_SUCCESS;
00153 }
00154
00155
static int handle_set_debug(
int fd,
int argc,
char *argv[])
00156 {
00157
int val = 0;
00158
int oldval = 0;
00159
00160
if ((argc != 3) && (argc != 4))
00161
return RESULT_SHOWUSAGE;
00162
if ((argc == 4) && strcasecmp(argv[2],
"atleast"))
00163
return RESULT_SHOWUSAGE;
00164 oldval =
option_debug;
00165
if (argc == 3)
00166
option_debug = atoi(argv[2]);
00167
else {
00168 val = atoi(argv[3]);
00169
if (val >
option_debug)
00170
option_debug = val;
00171 }
00172
if (oldval !=
option_debug &&
option_debug > 0)
00173
ast_cli(fd,
"Core debug was %d and is now %d\n", oldval, option_debug);
00174
else if (oldval > 0 &&
option_debug > 0)
00175
ast_cli(fd,
"Core debug is atleast %d\n", option_debug);
00176
else if (oldval > 0 &&
option_debug == 0)
00177
ast_cli(fd,
"Core debug is now OFF\n");
00178
return RESULT_SUCCESS;
00179 }
00180
00181
static int handle_unload(
int fd,
int argc,
char *argv[])
00182 {
00183
int x;
00184
int force=
AST_FORCE_SOFT;
00185
if (argc < 2)
00186
return RESULT_SHOWUSAGE;
00187
for (x=1;x<argc;x++) {
00188
if (argv[x][0] ==
'-') {
00189
switch(argv[x][1]) {
00190
case 'f':
00191 force =
AST_FORCE_FIRM;
00192
break;
00193
case 'h':
00194 force =
AST_FORCE_HARD;
00195
break;
00196
default:
00197
return RESULT_SHOWUSAGE;
00198 }
00199 }
else if (x != argc - 1)
00200
return RESULT_SHOWUSAGE;
00201
else if (
ast_unload_resource(argv[x], force)) {
00202
ast_cli(fd,
"Unable to unload resource %s\n", argv[x]);
00203
return RESULT_FAILURE;
00204 }
00205 }
00206
return RESULT_SUCCESS;
00207 }
00208
00209
#define MODLIST_FORMAT "%-25s %-40.40s %-10d\n"
00210 #define MODLIST_FORMAT2 "%-25s %-40.40s %-10s\n"
00211
00212
AST_MUTEX_DEFINE_STATIC(climodentrylock);
00213
static int climodentryfd = -1;
00214
00215
static int modlist_modentry(
char *
module,
char *description,
int usecnt)
00216 {
00217
ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt);
00218
return 0;
00219 }
00220
00221
static char modlist_help[] =
00222
"Usage: show modules\n"
00223
" Shows Asterisk modules currently in use, and usage "
00224
"statistics.\n";
00225
00226
static char version_help[] =
00227
"Usage: show version\n"
00228
" Shows Asterisk version information.\n ";
00229
00230
static char *format_uptimestr(time_t timeval)
00231 {
00232
int years = 0, weeks = 0, days = 0, hours = 0, mins = 0, secs = 0;
00233
char timestr[256]=
"";
00234
int bytes = 0;
00235
int maxbytes = 0;
00236
int offset = 0;
00237
#define SECOND (1)
00238
#define MINUTE (SECOND*60)
00239
#define HOUR (MINUTE*60)
00240
#define DAY (HOUR*24)
00241
#define WEEK (DAY*7)
00242
#define YEAR (DAY*365)
00243
#define ESS(x) ((x == 1) ? "" : "s")
00244
00245 maxbytes =
sizeof(timestr);
00246
if (timeval < 0)
00247
return NULL;
00248
if (timeval >
YEAR) {
00249 years = (timeval /
YEAR);
00250 timeval -= (years *
YEAR);
00251
if (years > 0) {
00252 snprintf(timestr + offset, maxbytes,
"%d year%s, ", years,
ESS(years));
00253 bytes = strlen(timestr + offset);
00254 offset += bytes;
00255 maxbytes -= bytes;
00256 }
00257 }
00258
if (timeval >
WEEK) {
00259 weeks = (timeval /
WEEK);
00260 timeval -= (weeks *
WEEK);
00261
if (weeks > 0) {
00262 snprintf(timestr + offset, maxbytes,
"%d week%s, ", weeks,
ESS(weeks));
00263 bytes = strlen(timestr + offset);
00264 offset += bytes;
00265 maxbytes -= bytes;
00266 }
00267 }
00268
if (timeval >
DAY) {
00269 days = (timeval /
DAY);
00270 timeval -= (days *
DAY);
00271
if (days > 0) {
00272 snprintf(timestr + offset, maxbytes,
"%d day%s, ", days,
ESS(days));
00273 bytes = strlen(timestr + offset);
00274 offset += bytes;
00275 maxbytes -= bytes;
00276 }
00277 }
00278
if (timeval >
HOUR) {
00279 hours = (timeval /
HOUR);
00280 timeval -= (hours *
HOUR);
00281
if (hours > 0) {
00282 snprintf(timestr + offset, maxbytes,
"%d hour%s, ", hours,
ESS(hours));
00283 bytes = strlen(timestr + offset);
00284 offset += bytes;
00285 maxbytes -= bytes;
00286 }
00287 }
00288
if (timeval >
MINUTE) {
00289 mins = (timeval /
MINUTE);
00290 timeval -= (mins *
MINUTE);
00291
if (mins > 0) {
00292 snprintf(timestr + offset, maxbytes,
"%d minute%s, ", mins,
ESS(mins));
00293 bytes = strlen(timestr + offset);
00294 offset += bytes;
00295 maxbytes -= bytes;
00296 }
00297 }
00298 secs = timeval;
00299
00300
if (secs > 0) {
00301 snprintf(timestr + offset, maxbytes,
"%d second%s", secs,
ESS(secs));
00302 }
00303
00304
return timestr ?
strdup(timestr) : NULL;
00305 }
00306
00307
static int handle_showuptime(
int fd,
int argc,
char *argv[])
00308 {
00309 time_t curtime, tmptime;
00310
char *timestr;
00311
00312 time(&curtime);
00313
if (
ast_startuptime) {
00314 tmptime = curtime -
ast_startuptime;
00315 timestr = format_uptimestr(tmptime);
00316
if (timestr) {
00317
ast_cli(fd,
"System uptime: %s\n", timestr);
00318
free(timestr);
00319 }
00320 }
00321
if (
ast_lastreloadtime) {
00322 tmptime = curtime -
ast_lastreloadtime;
00323 timestr = format_uptimestr(tmptime);
00324
if (timestr) {
00325
ast_cli(fd,
"Last reload: %s\n", timestr);
00326
free(timestr);
00327 }
00328 }
00329
return RESULT_SUCCESS;
00330 }
00331
00332
static int handle_modlist(
int fd,
int argc,
char *argv[])
00333 {
00334
if (argc != 2)
00335
return RESULT_SHOWUSAGE;
00336
ast_mutex_lock(&climodentrylock);
00337 climodentryfd = fd;
00338
ast_cli(fd, MODLIST_FORMAT2,
"Module",
"Description",
"Use Count");
00339
ast_update_module_list(modlist_modentry);
00340 climodentryfd = -1;
00341
ast_mutex_unlock(&climodentrylock);
00342
return RESULT_SUCCESS;
00343 }
00344
00345
static int handle_version(
int fd,
int argc,
char *argv[])
00346 {
00347
if (argc != 2)
00348
return RESULT_SHOWUSAGE;
00349
ast_cli(fd,
"%s\n", VERSION_INFO);
00350
return RESULT_SUCCESS;
00351 }
00352
static int handle_chanlist(
int fd,
int argc,
char *argv[])
00353 {
00354
#define FORMAT_STRING "%15s (%-10s %-12s %-4d) %7s %-12s %-15s\n"
00355
#define FORMAT_STRING2 "%15s (%-10s %-12s %-4s) %7s %-12s %-15s\n"
00356
#define CONCISE_FORMAT_STRING "%s:%s:%s:%d:%s:%s:%s:%s:%s:%d\n"
00357
00358
struct ast_channel *c=NULL;
00359
int numchans = 0;
00360
int concise = 0;
00361
if (argc < 2 || argc > 3)
00362
return RESULT_SHOWUSAGE;
00363
00364 concise = (argc == 3 && (!strcasecmp(argv[2],
"concise")));
00365 c =
ast_channel_walk_locked(NULL);
00366
if(!concise)
00367
ast_cli(fd, FORMAT_STRING2,
"Channel",
"Context",
"Extension",
"Pri",
"State",
"Appl.",
"Data");
00368
while(c) {
00369
if(concise)
00370
ast_cli(fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority,
ast_state2str(c->_state),
00371 c->appl ? c->appl :
"(None)", c->data ? ( !ast_strlen_zero(c->data) ? c->data :
"" ):
"",
00372 (c->callerid && !ast_strlen_zero(c->callerid)) ? c->callerid :
"",
00373 (c->accountcode && !ast_strlen_zero(c->accountcode)) ? c->accountcode :
"",c->amaflags);
00374
else
00375
ast_cli(fd, FORMAT_STRING, c->name, c->context, c->exten, c->priority,
ast_state2str(c->_state),
00376 c->appl ? c->appl :
"(None)", c->data ? ( !ast_strlen_zero(c->data) ? c->data :
"(Empty)" ):
"(None)");
00377
00378 numchans++;
00379
ast_mutex_unlock(&c->lock);
00380 c =
ast_channel_walk_locked(c);
00381 }
00382
if(!concise)
00383
ast_cli(fd,
"%d active channel(s)\n", numchans);
00384
return RESULT_SUCCESS;
00385 }
00386
00387
static char showchan_help[] =
00388
"Usage: show channel <channel>\n"
00389
" Shows lots of information about the specified channel.\n";
00390
00391
static char debugchan_help[] =
00392
"Usage: debug channel <channel>\n"
00393
" Enables debugging on a specific channel.\n";
00394
00395
static char nodebugchan_help[] =
00396
"Usage: no debug channel <channel>\n"
00397
" Disables debugging on a specific channel.\n";
00398
00399
static char commandcomplete_help[] =
00400
"Usage: _command complete \"<line>\" text state\n"
00401
" This function is used internally to help with command completion and should.\n"
00402
" never be called by the user directly.\n";
00403
00404
static char commandnummatches_help[] =
00405
"Usage: _command nummatches \"<line>\" text \n"
00406
" This function is used internally to help with command completion and should.\n"
00407
" never be called by the user directly.\n";
00408
00409
static char commandmatchesarray_help[] =
00410
"Usage: _command matchesarray \"<line>\" text \n"
00411
" This function is used internally to help with command completion and should.\n"
00412
" never be called by the user directly.\n";
00413
00414
static int handle_softhangup(
int fd,
int argc,
char *argv[])
00415 {
00416
struct ast_channel *c=NULL;
00417
if (argc != 3)
00418
return RESULT_SHOWUSAGE;
00419 c =
ast_channel_walk_locked(NULL);
00420
while(c) {
00421
if (!strcasecmp(c->name, argv[2])) {
00422
ast_cli(fd,
"Requested Hangup on channel '%s'\n", c->name);
00423
ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
00424
ast_mutex_unlock(&c->lock);
00425
break;
00426 }
00427
ast_mutex_unlock(&c->lock);
00428 c =
ast_channel_walk_locked(c);
00429 }
00430
if (!c)
00431
ast_cli(fd,
"%s is not a known channel\n", argv[2]);
00432
return RESULT_SUCCESS;
00433 }
00434
00435
static char *__ast_cli_generator(
char *text,
char *word,
int state,
int lock);
00436
00437
static int handle_commandmatchesarray(
int fd,
int argc,
char *argv[])
00438 {
00439
char *buf;
00440
int buflen = 2048;
00441
int len = 0;
00442
char **matches;
00443
int x;
00444
00445
if (argc != 4)
00446
return RESULT_SHOWUSAGE;
00447 buf =
malloc(buflen);
00448
if (!buf)
00449
return RESULT_FAILURE;
00450 buf[len] =
'\0';
00451 matches =
ast_cli_completion_matches(argv[2], argv[3]);
00452
if (matches) {
00453
for (x=0; matches[x]; x++) {
00454
#if 0
00455
printf(
"command matchesarray for '%s' %s got '%s'\n", argv[2], argv[3], matches[x]);
00456
#endif
00457
if (len + strlen(matches[x]) >= buflen) {
00458 buflen += strlen(matches[x]) * 3;
00459 buf =
realloc(buf, buflen);
00460 }
00461 len += sprintf( buf + len,
"%s ", matches[x]);
00462
free(matches[x]);
00463 matches[x] = NULL;
00464 }
00465
free(matches);
00466 }
00467
#if 0
00468
printf(
"array for '%s' %s got '%s'\n", argv[2], argv[3], buf);
00469
#endif
00470
00471
if (buf) {
00472
ast_cli(fd,
"%s%s",buf, AST_CLI_COMPLETE_EOF);
00473
free(buf);
00474 }
else
00475
ast_cli(fd,
"NULL\n");
00476
00477
return RESULT_SUCCESS;
00478 }
00479
00480
00481
00482
static int handle_commandnummatches(
int fd,
int argc,
char *argv[])
00483 {
00484
int matches = 0;
00485
00486
if (argc != 4)
00487
return RESULT_SHOWUSAGE;
00488
00489 matches =
ast_cli_generatornummatches(argv[2], argv[3]);
00490
00491
#if 0
00492
printf(
"Search for '%s' %s got '%d'\n", argv[2], argv[3], matches);
00493
#endif
00494
ast_cli(fd,
"%d", matches);
00495
00496
return RESULT_SUCCESS;
00497 }
00498
00499
static int handle_commandcomplete(
int fd,
int argc,
char *argv[])
00500 {
00501
char *buf;
00502
#if 0
00503
printf(
"Search for %d args: '%s', '%s', '%s', '%s'\n", argc, argv[0], argv[1], argv[2], argv[3]);
00504
#endif
00505
if (argc != 5)
00506
return RESULT_SHOWUSAGE;
00507 buf = __ast_cli_generator(argv[2], argv[3], atoi(argv[4]), 0);
00508
#if 0
00509
printf(
"Search for '%s' %s %d got '%s'\n", argv[2], argv[3], atoi(argv[4]), buf);
00510
#endif
00511
if (buf) {
00512
ast_cli(fd, buf);
00513
free(buf);
00514 }
else
00515
ast_cli(fd,
"NULL\n");
00516
return RESULT_SUCCESS;
00517 }
00518
00519
static int handle_debugchan(
int fd,
int argc,
char *argv[])
00520 {
00521
struct ast_channel *c=NULL;
00522
if (argc != 3)
00523
return RESULT_SHOWUSAGE;
00524 c =
ast_channel_walk_locked(NULL);
00525
while(c) {
00526
if (!strcasecmp(c->name, argv[2])) {
00527 c->fin |= 0x80000000;
00528 c->fout |= 0x80000000;
00529
break;
00530 }
00531
ast_mutex_unlock(&c->lock);
00532 c =
ast_channel_walk_locked(c);
00533 }
00534
if (c) {
00535
ast_cli(fd,
"Debugging enabled on channel %s\n", c->name);
00536
ast_mutex_unlock(&c->lock);
00537 }
00538
else
00539
ast_cli(fd,
"No such channel %s\n", argv[2]);
00540
return RESULT_SUCCESS;
00541 }
00542
00543
static int handle_nodebugchan(
int fd,
int argc,
char *argv[])
00544 {
00545
struct ast_channel *c=NULL;
00546
if (argc != 4)
00547
return RESULT_SHOWUSAGE;
00548 c =
ast_channel_walk_locked(NULL);
00549
while(c) {
00550
if (!strcasecmp(c->name, argv[3])) {
00551 c->fin &= 0x7fffffff;
00552 c->fout &= 0x7fffffff;
00553
break;
00554 }
00555
ast_mutex_unlock(&c->lock);
00556 c =
ast_channel_walk_locked(c);
00557 }
00558
if (c) {
00559
ast_cli(fd,
"Debugging disabled on channel %s\n", c->name);
00560
ast_mutex_unlock(&c->lock);
00561 }
else
00562
ast_cli(fd,
"No such channel %s\n", argv[2]);
00563
return RESULT_SUCCESS;
00564 }
00565
00566
00567
00568
static int handle_showchan(
int fd,
int argc,
char *argv[])
00569 {
00570
struct ast_channel *c=NULL;
00571
struct timeval now;
00572
long elapsed_seconds=0;
00573
int hour=0, min=0, sec=0;
00574
if (argc != 3)
00575
return RESULT_SHOWUSAGE;
00576 gettimeofday(&now, NULL);
00577 c =
ast_channel_walk_locked(NULL);
00578
while(c) {
00579
if (!strcasecmp(c->name, argv[2])) {
00580
if(c->cdr) {
00581 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
00582 hour = elapsed_seconds / 3600;
00583 min = (elapsed_seconds % 3600) / 60;
00584 sec = elapsed_seconds % 60;
00585 }
00586
ast_cli(fd,
00587
" -- General --\n"
00588
" Name: %s\n"
00589
" Type: %s\n"
00590
" UniqueID: %s\n"
00591
" Caller ID: %s\n"
00592
" DNID Digits: %s\n"
00593
" State: %s (%d)\n"
00594
" Rings: %d\n"
00595
" NativeFormat: %d\n"
00596
" WriteFormat: %d\n"
00597
" ReadFormat: %d\n"
00598
"1st File Descriptor: %d\n"
00599
" Frames in: %d%s\n"
00600
" Frames out: %d%s\n"
00601
" Time to Hangup: %ld\n"
00602
" Elapsed Time: %dh%dm%ds\n"
00603
" -- PBX --\n"
00604
" Context: %s\n"
00605
" Extension: %s\n"
00606
" Priority: %d\n"
00607
" Call Group: %d\n"
00608
" Pickup Group: %d\n"
00609
" Application: %s\n"
00610
" Data: %s\n"
00611
" Stack: %d\n"
00612
" Blocking in: %s\n",
00613 c->name, c->type, c->uniqueid,
00614 (c->callerid ? c->callerid :
"(N/A)"),
00615 (c->dnid ? c->dnid :
"(N/A)" ),
ast_state2str(c->_state), c->_state, c->rings, c->nativeformats, c->writeformat, c->readformat,
00616 c->fds[0], c->fin & 0x7fffffff, (c->fin & 0x80000000) ?
" (DEBUGGED)" :
"",
00617 c->fout & 0x7fffffff, (c->fout & 0x80000000) ?
" (DEBUGGED)" :
"", (
long)c->whentohangup,
00618 hour, min, sec,
00619 c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl :
"(N/A)" ),
00620 ( c-> data ? (!ast_strlen_zero(c->data) ? c->data :
"(Empty)") :
"(None)"),
00621 c->stack, (c->blocking ? c->blockproc :
"(Not Blocking)"));
00622
ast_mutex_unlock(&c->lock);
00623
break;
00624 }
00625
ast_mutex_unlock(&c->lock);
00626 c =
ast_channel_walk_locked(c);
00627 }
00628
if (!c)
00629
ast_cli(fd,
"%s is not a known channel\n", argv[2]);
00630
return RESULT_SUCCESS;
00631 }
00632
00633
static char *complete_ch_helper(
char *line,
char *word,
int pos,
int state,
int rpos)
00634 {
00635
struct ast_channel *c;
00636
int which=0;
00637
char *ret;
00638
if (pos != rpos)
00639
return NULL;
00640 c =
ast_channel_walk_locked(NULL);
00641
while(c) {
00642
if (!strncasecmp(word, c->name, strlen(word))) {
00643
if (++which > state)
00644
break;
00645 }
00646
ast_mutex_unlock(&c->lock);
00647 c =
ast_channel_walk_locked(c);
00648 }
00649
if (c) {
00650 ret =
strdup(c->name);
00651
ast_mutex_unlock(&c->lock);
00652 }
else
00653 ret = NULL;
00654
return ret;
00655 }
00656
00657
static char *complete_ch_3(
char *line,
char *word,
int pos,
int state)
00658 {
00659
return complete_ch_helper(line, word, pos, state, 2);
00660 }
00661
00662
static char *complete_ch_4(
char *line,
char *word,
int pos,
int state)
00663 {
00664
return complete_ch_helper(line, word, pos, state, 3);
00665 }
00666
00667
static char *complete_fn(
char *line,
char *word,
int pos,
int state)
00668 {
00669
char *c;
00670
char filename[256];
00671
if (pos != 1)
00672
return NULL;
00673
if (word[0] ==
'/')
00674 strncpy(filename, word,
sizeof(filename)-1);
00675
else
00676 snprintf(filename,
sizeof(filename),
"%s/%s", (
char *)ast_config_AST_MODULE_DIR, word);
00677 c = (
char*)filename_completion_function(filename, state);
00678
if (c && word[0] !=
'/')
00679 c += (strlen((
char*)ast_config_AST_MODULE_DIR) + 1);
00680
return c ?
strdup(c) : c;
00681 }
00682
00683
static int handle_help(
int fd,
int argc,
char *argv[]);
00684
00685
static struct ast_cli_entry builtins[] = {
00686
00687 { {
"_command",
"complete", NULL }, handle_commandcomplete,
"Command complete", commandcomplete_help },
00688 { {
"_command",
"nummatches", NULL }, handle_commandnummatches,
"Returns number of command matches", commandnummatches_help },
00689 { {
"_command",
"matchesarray", NULL }, handle_commandmatchesarray,
"Returns command matches array", commandmatchesarray_help },
00690 { {
"debug",
"channel", NULL }, handle_debugchan,
"Enable debugging on a channel", debugchan_help, complete_ch_3 },
00691 { {
"help", NULL }, handle_help,
"Display help list, or specific help on a command", help_help },
00692 { {
"load", NULL }, handle_load,
"Load a dynamic module by name", load_help, complete_fn },
00693 { {
"no",
"debug",
"channel", NULL }, handle_nodebugchan,
"Disable debugging on a channel", nodebugchan_help, complete_ch_4 },
00694 { {
"reload", NULL }, handle_reload,
"Reload configuration", reload_help },
00695 { {
"set",
"debug", NULL }, handle_set_debug,
"Set level of debug chattiness", set_debug_help },
00696 { {
"set",
"verbose", NULL }, handle_set_verbose,
"Set level of verboseness", set_verbose_help },
00697 { {
"show",
"channels", NULL }, handle_chanlist,
"Display information on channels", chanlist_help },
00698 { {
"show",
"channel", NULL }, handle_showchan,
"Display information on a specific channel", showchan_help, complete_ch_3 },
00699 { {
"show",
"modules", NULL }, handle_modlist,
"List modules and info", modlist_help },
00700 { {
"show",
"uptime", NULL }, handle_showuptime,
"Show uptime information", modlist_help },
00701 { {
"show",
"version", NULL }, handle_version,
"Display version info", version_help },
00702 { {
"soft",
"hangup", NULL }, handle_softhangup,
"Request a hangup on a given channel", softhangup_help, complete_ch_3 },
00703 { {
"unload", NULL }, handle_unload,
"Unload a dynamic module by name", unload_help, complete_fn },
00704 { { NULL }, NULL, NULL, NULL }
00705 };
00706
00707
static struct ast_cli_entry *find_cli(
char *cmds[],
int exact)
00708 {
00709
int x;
00710
int y;
00711
int match;
00712
struct ast_cli_entry *e=NULL;
00713
for (x=0;builtins[x].
cmda[0];x++) {
00714
00715 match = 1;
00716
for (y=0;match && cmds[y]; y++) {
00717
00718
00719
if (!builtins[x].
cmda[y] && !exact)
00720
break;
00721
00722
00723
00724
if (!builtins[x].
cmda[y] || strcasecmp(builtins[x].cmda[y], cmds[y]))
00725 match = 0;
00726 }
00727
00728
00729
if ((exact > -1) && builtins[x].
cmda[y])
00730 match = 0;
00731
if (match)
00732
return &builtins[x];
00733 }
00734
for (e=
helpers;e;e=e->
next) {
00735 match = 1;
00736
for (y=0;match && cmds[y]; y++) {
00737
if (!e->cmda[y] && !exact)
00738
break;
00739
if (!e->cmda[y] || strcasecmp(e->cmda[y], cmds[y]))
00740 match = 0;
00741 }
00742
if ((exact > -1) && e->cmda[y])
00743 match = 0;
00744
if (match)
00745
break;
00746 }
00747
return e;
00748 }
00749
00750
static void join(
char *dest, size_t destsize,
char *w[])
00751 {
00752
int x;
00753
00754
if (!dest || destsize < 1) {
00755
return;
00756 }
00757 dest[0] =
'\0';
00758
for (x=0;w[x];x++) {
00759
if (x)
00760 strncat(dest,
" ", destsize - strlen(dest) - 1);
00761 strncat(dest, w[x], destsize - strlen(dest) - 1);
00762 }
00763 }
00764
00765
static void join2(
char *dest, size_t destsize,
char *w[])
00766 {
00767
int x;
00768
00769
if (!dest || destsize < 1) {
00770
return;
00771 }
00772 dest[0] =
'\0';
00773
for (x=0;w[x];x++) {
00774 strncat(dest, w[x], destsize - strlen(dest) - 1);
00775 }
00776 }
00777
00778
static char *find_best(
char *argv[])
00779 {
00780
static char cmdline[80];
00781
int x;
00782
00783
char *myargv[
AST_MAX_CMD_LEN];
00784
for (x=0;x<
AST_MAX_CMD_LEN;x++)
00785 myargv[x]=NULL;
00786
for (x=0;argv[x];x++) {
00787 myargv[x] = argv[x];
00788
if (!find_cli(myargv, -1))
00789
break;
00790 }
00791 join(cmdline,
sizeof(cmdline), myargv);
00792
return cmdline;
00793 }
00794
00795
int ast_cli_unregister(
struct ast_cli_entry *e)
00796 {
00797
struct ast_cli_entry *cur, *l=NULL;
00798
ast_mutex_lock(&clilock);
00799 cur =
helpers;
00800
while(cur) {
00801
if (e == cur) {
00802
if (e->
inuse) {
00803
ast_log(
LOG_WARNING,
"Can't remove command that is in use\n");
00804 }
else {
00805
00806
if (l)
00807 l->next = e->
next;
00808
else
00809
helpers = e->
next;
00810 e->
next = NULL;
00811
break;
00812 }
00813 }
00814 l = cur;
00815 cur = cur->
next;
00816 }
00817
ast_mutex_unlock(&clilock);
00818
return 0;
00819 }
00820
00821
int ast_cli_register(
struct ast_cli_entry *e)
00822 {
00823
struct ast_cli_entry *cur, *l=NULL;
00824
char fulle[80] =
"", fulltst[80] =
"";
00825
static int len;
00826
ast_mutex_lock(&clilock);
00827 join2(fulle,
sizeof(fulle), e->
cmda);
00828
if (find_cli(e->
cmda, -1)) {
00829
ast_mutex_unlock(&clilock);
00830
ast_log(
LOG_WARNING,
"Command '%s' already registered (or something close enough)\n", fulle);
00831
return -1;
00832 }
00833 cur =
helpers;
00834
while(cur) {
00835 join2(fulltst,
sizeof(fulltst), cur->cmda);
00836 len = strlen(fulltst);
00837
if (strlen(fulle) < len)
00838 len = strlen(fulle);
00839
if (strncasecmp(fulle, fulltst, len) < 0) {
00840
if (l) {
00841 e->
next = l->
next;
00842 l->
next = e;
00843 }
else {
00844 e->
next =
helpers;
00845
helpers = e;
00846 }
00847
break;
00848 }
00849 l = cur;
00850 cur = cur->
next;
00851 }
00852
if (!cur) {
00853
if (l)
00854 l->
next = e;
00855
else
00856
helpers = e;
00857 e->
next = NULL;
00858 }
00859
ast_mutex_unlock(&clilock);
00860
return 0;
00861 }
00862
00863
static int help_workhorse(
int fd,
char *match[])
00864 {
00865
char fullcmd1[80];
00866
char fullcmd2[80];
00867
char matchstr[80];
00868
char *fullcmd;
00869
struct ast_cli_entry *e, *e1, *e2;
00870 e1 = builtins;
00871 e2 =
helpers;
00872
if (match)
00873 join(matchstr,
sizeof(matchstr), match);
00874
while(e1->cmda[0] || e2) {
00875
if (e2)
00876 join(fullcmd2,
sizeof(fullcmd2), e2->cmda);
00877
if (e1->cmda[0])
00878 join(fullcmd1,
sizeof(fullcmd1), e1->cmda);
00879
if (!e1->cmda[0] ||
00880 (e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
00881
00882 e = e2;
00883 fullcmd = fullcmd2;
00884
00885 e2 = e2->next;
00886 }
else {
00887
00888 e = e1;
00889 fullcmd = fullcmd1;
00890 e1++;
00891 }
00892
00893
if (fullcmd[0] ==
'_')
00894
continue;
00895
if (match) {
00896
if (strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
00897
continue;
00898 }
00899 }
00900
ast_cli(fd,
"%25.25s %s\n", fullcmd, e->summary);
00901 }
00902
return 0;
00903 }
00904
00905
static int handle_help(
int fd,
int argc,
char *argv[]) {
00906
struct ast_cli_entry *e;
00907
char fullcmd[80];
00908
if ((argc < 1))
00909
return RESULT_SHOWUSAGE;
00910
if (argc > 1) {
00911 e = find_cli(argv + 1, 1);
00912
if (e)
00913
ast_cli(fd, e->usage);
00914
else {
00915
if (find_cli(argv + 1, -1)) {
00916
return help_workhorse(fd, argv + 1);
00917 }
else {
00918 join(fullcmd,
sizeof(fullcmd), argv+1);
00919
ast_cli(fd,
"No such command '%s'.\n", fullcmd);
00920 }
00921 }
00922 }
else {
00923
return help_workhorse(fd, NULL);
00924 }
00925
return RESULT_SUCCESS;
00926 }
00927
00928
static char *parse_args(
char *s,
int *max,
char *argv[])
00929 {
00930
char *dup, *cur;
00931
int x=0;
00932
int quoted=0;
00933
int escaped=0;
00934
int whitespace=1;
00935
00936 dup =
strdup(s);
00937
if (dup) {
00938 cur = dup;
00939
while(*s) {
00940
switch(*s) {
00941
case '"':
00942
00943
if (escaped)
00944
goto normal;
00945
else
00946 quoted = !quoted;
00947
if (quoted && whitespace) {
00948
00949 argv[x++] = cur;
00950 whitespace=0;
00951 }
00952 escaped = 0;
00953
break;
00954
case ' ':
00955
case '\t':
00956
if (!quoted && !escaped) {
00957
00958
00959 whitespace = 1;
00960 *(cur++) =
'\0';
00961 }
else
00962
00963
goto normal;
00964
break;
00965
case '\\':
00966
00967
if (escaped) {
00968
goto normal;
00969 }
else {
00970 escaped=1;
00971 }
00972
break;
00973
default:
00974 normal:
00975
if (whitespace) {
00976
if (x >=
AST_MAX_ARGS -1) {
00977
ast_log(LOG_WARNING,
"Too many arguments, truncating\n");
00978
break;
00979 }
00980
00981 argv[x++] = cur;
00982 whitespace=0;
00983 }
00984 *(cur++) = *
s;
00985 escaped=0;
00986 }
00987
s++;
00988 }
00989
00990 *(cur++) =
'\0';
00991 argv[x] = NULL;
00992 *max = x;
00993 }
00994
return dup;
00995 }
00996
00997
00998
int ast_cli_generatornummatches(
char *text,
char *word)
00999 {
01000
int matches = 0, i = 0;
01001
char *buf, *oldbuf = NULL;
01002
01003
01004
while ( (buf =
ast_cli_generator(text, word, i)) ) {
01005
if (++i > 1 && strcmp(buf,oldbuf) == 0) {
01006
continue;
01007 }
01008 oldbuf = buf;
01009 matches++;
01010 }
01011
01012
return matches;
01013 }
01014
01015
char **
ast_cli_completion_matches(
char *text,
char *word)
01016 {
01017
char **match_list = NULL, *retstr, *prevstr;
01018 size_t match_list_len, max_equal, which, i;
01019
int matches = 0;
01020
01021 match_list_len = 1;
01022
while ((retstr =
ast_cli_generator(text, word, matches)) != NULL) {
01023
if (matches + 1 >= match_list_len) {
01024 match_list_len <<= 1;
01025 match_list =
realloc(match_list, match_list_len *
sizeof(
char *));
01026 }
01027 match_list[++matches] = retstr;
01028 }
01029
01030
if (!match_list)
01031
return (
char **) NULL;
01032
01033 which = 2;
01034 prevstr = match_list[1];
01035 max_equal = strlen(prevstr);
01036
for (; which <= matches; which++) {
01037
for (i = 0; i < max_equal && prevstr[i] == match_list[which][i]; i++)
01038
continue;
01039 max_equal = i;
01040 }
01041
01042 retstr =
malloc(max_equal + 1);
01043 (
void) strncpy(retstr, match_list[1], max_equal);
01044 retstr[max_equal] =
'\0';
01045 match_list[0] = retstr;
01046
01047
if (matches + 1 >= match_list_len)
01048 match_list =
realloc(match_list, (match_list_len + 1) *
sizeof(
char *));
01049 match_list[matches + 1] = (
char *) NULL;
01050
01051
return (match_list);
01052 }
01053
01054
static char *__ast_cli_generator(
char *text,
char *word,
int state,
int lock)
01055 {
01056
char *argv[
AST_MAX_ARGS];
01057
struct ast_cli_entry *e, *e1, *e2;
01058
int x;
01059
int matchnum=0;
01060
char *dup, *res;
01061
char fullcmd1[80];
01062
char fullcmd2[80];
01063
char matchstr[80];
01064
char *fullcmd;
01065
01066
if ((dup = parse_args(text, &x, argv))) {
01067 join(matchstr,
sizeof(matchstr), argv);
01068
if (lock)
01069
ast_mutex_lock(&clilock);
01070 e1 = builtins;
01071 e2 =
helpers;
01072
while(e1->cmda[0] || e2) {
01073
if (e2)
01074 join(fullcmd2,
sizeof(fullcmd2), e2->cmda);
01075
if (e1->cmda[0])
01076 join(fullcmd1,
sizeof(fullcmd1), e1->cmda);
01077
if (!e1->cmda[0] ||
01078 (e2 && (strcmp(fullcmd2, fullcmd1) < 0))) {
01079
01080 e = e2;
01081 fullcmd = fullcmd2;
01082
01083 e2 = e2->next;
01084 }
else {
01085
01086 e = e1;
01087 fullcmd = fullcmd1;
01088 e1++;
01089 }
01090
if ((fullcmd[0] !=
'_') && !strncasecmp(matchstr, fullcmd, strlen(matchstr))) {
01091
01092 matchnum++;
01093
if (matchnum > state) {
01094
01095
if (!ast_strlen_zero(word) && x>0) {
01096 res = e->cmda[x-1];
01097 }
else {
01098 res = e->cmda[x];
01099 }
01100
if (res) {
01101
if (lock)
01102
ast_mutex_unlock(&clilock);
01103
free(dup);
01104
return res ?
strdup(res) : NULL;
01105 }
01106 }
01107 }
01108
if (e->generator && !strncasecmp(matchstr, fullcmd, strlen(fullcmd))) {
01109
01110
01111 fullcmd = e->generator(matchstr, word, (!ast_strlen_zero(word) ? (x - 1) : (x)), state);
01112
if (lock)
01113
ast_mutex_unlock(&clilock);
01114
free(dup);
01115
return fullcmd;
01116 }
01117
01118 }
01119
if (lock)
01120
ast_mutex_unlock(&clilock);
01121
free(dup);
01122 }
01123
return NULL;
01124 }
01125
01126
char *
ast_cli_generator(
char *text,
char *word,
int state)
01127 {
01128
return __ast_cli_generator(text, word, state, 1);
01129 }
01130
01131
int ast_cli_command(
int fd,
char *s)
01132 {
01133
char *argv[
AST_MAX_ARGS];
01134
struct ast_cli_entry *e;
01135
int x;
01136
char *dup;
01137 x =
AST_MAX_ARGS;
01138
if ((dup = parse_args(
s, &x, argv))) {
01139
01140
if (x > 0) {
01141
ast_mutex_lock(&clilock);
01142 e = find_cli(argv, 0);
01143
if (e)
01144 e->inuse++;
01145
ast_mutex_unlock(&clilock);
01146
if (e) {
01147
switch(e->handler(fd, x, argv)) {
01148
case RESULT_SHOWUSAGE:
01149
ast_cli(fd, e->usage);
01150
break;
01151 }
01152 }
else
01153
ast_cli(fd,
"No such command '%s' (type 'help' for help)\n", find_best(argv));
01154
if (e) {
01155
ast_mutex_lock(&clilock);
01156 e->inuse--;
01157
ast_mutex_unlock(&clilock);
01158 }
01159 }
01160
free(dup);
01161 }
else {
01162
ast_log(
LOG_WARNING,
"Out of memory\n");
01163
return -1;
01164 }
01165
return 0;
01166 }
01167