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