00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 313860 $")
00029
00030 #include "asterisk/_private.h"
00031 #include "asterisk/paths.h"
00032 #include <sys/signal.h>
00033 #include <signal.h>
00034 #include <ctype.h>
00035 #include <regex.h>
00036 #include <pwd.h>
00037 #include <grp.h>
00038
00039 #include <readline.h>
00040
00041 #include "asterisk/cli.h"
00042 #include "asterisk/linkedlists.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/lock.h"
00049 #include "asterisk/threadstorage.h"
00050 #include "asterisk/translate.h"
00051
00052
00053
00054
00055 struct cli_perm {
00056 unsigned int permit:1;
00057 char *command;
00058 AST_LIST_ENTRY(cli_perm) list;
00059 };
00060
00061 AST_LIST_HEAD_NOLOCK(cli_perm_head, cli_perm);
00062
00063
00064 struct usergroup_cli_perm {
00065 int uid;
00066 int gid;
00067 struct cli_perm_head *perms;
00068 AST_LIST_ENTRY(usergroup_cli_perm) list;
00069 };
00070
00071 static const char perms_config[] = "cli_permissions.conf";
00072
00073 static int cli_default_perm = 1;
00074
00075
00076
00077 AST_MUTEX_DEFINE_STATIC(permsconfiglock);
00078
00079 static AST_RWLIST_HEAD_STATIC(cli_perms, usergroup_cli_perm);
00080
00081
00082
00083
00084 struct module_level {
00085 unsigned int level;
00086 AST_RWLIST_ENTRY(module_level) entry;
00087 char module[0];
00088 };
00089
00090 AST_RWLIST_HEAD(module_level_list, module_level);
00091
00092
00093 static struct module_level_list debug_modules;
00094
00095 static struct module_level_list verbose_modules;
00096
00097 AST_THREADSTORAGE(ast_cli_buf);
00098
00099
00100 #define AST_CLI_INITLEN 256
00101
00102 void ast_cli(int fd, const char *fmt, ...)
00103 {
00104 int res;
00105 struct ast_str *buf;
00106 va_list ap;
00107
00108 if (!(buf = ast_str_thread_get(&ast_cli_buf, AST_CLI_INITLEN)))
00109 return;
00110
00111 va_start(ap, fmt);
00112 res = ast_str_set_va(&buf, 0, fmt, ap);
00113 va_end(ap);
00114
00115 if (res != AST_DYNSTR_BUILD_FAILED) {
00116 ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
00117 }
00118 }
00119
00120 unsigned int ast_debug_get_by_module(const char *module)
00121 {
00122 struct module_level *ml;
00123 unsigned int res = 0;
00124
00125 AST_RWLIST_RDLOCK(&debug_modules);
00126 AST_LIST_TRAVERSE(&debug_modules, ml, entry) {
00127 if (!strcasecmp(ml->module, module)) {
00128 res = ml->level;
00129 break;
00130 }
00131 }
00132 AST_RWLIST_UNLOCK(&debug_modules);
00133
00134 return res;
00135 }
00136
00137 unsigned int ast_verbose_get_by_module(const char *module)
00138 {
00139 struct module_level *ml;
00140 unsigned int res = 0;
00141
00142 AST_RWLIST_RDLOCK(&verbose_modules);
00143 AST_LIST_TRAVERSE(&verbose_modules, ml, entry) {
00144 if (!strcasecmp(ml->module, module)) {
00145 res = ml->level;
00146 break;
00147 }
00148 }
00149 AST_RWLIST_UNLOCK(&verbose_modules);
00150
00151 return res;
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 static int cli_has_permissions(int uid, int gid, const char *command)
00168 {
00169 struct usergroup_cli_perm *user_perm;
00170 struct cli_perm *perm;
00171
00172 int isallowg = cli_default_perm, isallowu = -1, ispattern;
00173 regex_t regexbuf;
00174
00175
00176
00177
00178 if ((uid == CLI_NO_PERMS && gid == CLI_NO_PERMS) || command[0] == '_') {
00179 return 1;
00180 }
00181
00182 if (gid < 0 && uid < 0) {
00183 return cli_default_perm;
00184 }
00185
00186 AST_RWLIST_RDLOCK(&cli_perms);
00187 AST_LIST_TRAVERSE(&cli_perms, user_perm, list) {
00188 if (user_perm->gid != gid && user_perm->uid != uid) {
00189 continue;
00190 }
00191 AST_LIST_TRAVERSE(user_perm->perms, perm, list) {
00192 if (strcasecmp(perm->command, "all") && strncasecmp(perm->command, command, strlen(perm->command))) {
00193
00194 ispattern = !regcomp(®exbuf, perm->command, REG_EXTENDED | REG_NOSUB | REG_ICASE);
00195 if (ispattern && regexec(®exbuf, command, 0, NULL, 0)) {
00196 regfree(®exbuf);
00197 continue;
00198 }
00199 if (!ispattern) {
00200 continue;
00201 }
00202 regfree(®exbuf);
00203 }
00204 if (user_perm->uid == uid) {
00205
00206 isallowu = perm->permit;
00207 } else {
00208
00209 isallowg = perm->permit;
00210 }
00211 }
00212 }
00213 AST_RWLIST_UNLOCK(&cli_perms);
00214 if (isallowu > -1) {
00215
00216 isallowg = isallowu;
00217 }
00218
00219 return isallowg;
00220 }
00221
00222 static AST_RWLIST_HEAD_STATIC(helpers, ast_cli_entry);
00223
00224 static char *complete_fn(const char *word, int state)
00225 {
00226 char *c, *d;
00227 char filename[PATH_MAX];
00228
00229 if (word[0] == '/')
00230 ast_copy_string(filename, word, sizeof(filename));
00231 else
00232 snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
00233
00234 c = d = filename_completion_function(filename, state);
00235
00236 if (c && word[0] != '/')
00237 c += (strlen(ast_config_AST_MODULE_DIR) + 1);
00238 if (c)
00239 c = ast_strdup(c);
00240
00241 free(d);
00242
00243 return c;
00244 }
00245
00246 static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00247 {
00248
00249 switch (cmd) {
00250 case CLI_INIT:
00251 e->command = "module load";
00252 e->usage =
00253 "Usage: module load <module name>\n"
00254 " Loads the specified module into Asterisk.\n";
00255 return NULL;
00256
00257 case CLI_GENERATE:
00258 if (a->pos != e->args)
00259 return NULL;
00260 return complete_fn(a->word, a->n);
00261 }
00262 if (a->argc != e->args + 1)
00263 return CLI_SHOWUSAGE;
00264 if (ast_load_resource(a->argv[e->args])) {
00265 ast_cli(a->fd, "Unable to load module %s\n", a->argv[e->args]);
00266 return CLI_FAILURE;
00267 }
00268 ast_cli(a->fd, "Loaded %s\n", a->argv[e->args]);
00269 return CLI_SUCCESS;
00270 }
00271
00272 static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00273 {
00274 int x;
00275
00276 switch (cmd) {
00277 case CLI_INIT:
00278 e->command = "module reload";
00279 e->usage =
00280 "Usage: module reload [module ...]\n"
00281 " Reloads configuration files for all listed modules which support\n"
00282 " reloading, or for all supported modules if none are listed.\n";
00283 return NULL;
00284
00285 case CLI_GENERATE:
00286 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 1);
00287 }
00288 if (a->argc == e->args) {
00289 ast_module_reload(NULL);
00290 return CLI_SUCCESS;
00291 }
00292 for (x = e->args; x < a->argc; x++) {
00293 int res = ast_module_reload(a->argv[x]);
00294
00295 switch (res) {
00296 case 0:
00297 ast_cli(a->fd, "No such module '%s'\n", a->argv[x]);
00298 break;
00299 case 1:
00300 ast_cli(a->fd, "Module '%s' does not support reload\n", a->argv[x]);
00301 break;
00302 }
00303 }
00304 return CLI_SUCCESS;
00305 }
00306
00307 static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00308 {
00309 switch (cmd) {
00310 case CLI_INIT:
00311 e->command = "core reload";
00312 e->usage =
00313 "Usage: core reload\n"
00314 " Execute a global reload.\n";
00315 return NULL;
00316
00317 case CLI_GENERATE:
00318 return NULL;
00319 }
00320
00321 if (a->argc != e->args) {
00322 return CLI_SHOWUSAGE;
00323 }
00324
00325 ast_module_reload(NULL);
00326
00327 return CLI_SUCCESS;
00328 }
00329
00330
00331
00332
00333 static struct module_level *find_module_level(const char *module, unsigned int debug)
00334 {
00335 struct module_level *ml;
00336 struct module_level_list *mll = debug ? &debug_modules : &verbose_modules;
00337
00338 AST_LIST_TRAVERSE(mll, ml, entry) {
00339 if (!strcasecmp(ml->module, module))
00340 return ml;
00341 }
00342
00343 return NULL;
00344 }
00345
00346 static char *complete_number(const char *partial, unsigned int min, unsigned int max, int n)
00347 {
00348 int i, count = 0;
00349 unsigned int prospective[2];
00350 unsigned int part = strtoul(partial, NULL, 10);
00351 char next[12];
00352
00353 if (part < min || part > max) {
00354 return NULL;
00355 }
00356
00357 for (i = 0; i < 21; i++) {
00358 if (i == 0) {
00359 prospective[0] = prospective[1] = part;
00360 } else if (part == 0 && !ast_strlen_zero(partial)) {
00361 break;
00362 } else if (i < 11) {
00363 prospective[0] = prospective[1] = part * 10 + (i - 1);
00364 } else {
00365 prospective[0] = (part * 10 + (i - 11)) * 10;
00366 prospective[1] = prospective[0] + 9;
00367 }
00368 if (i < 11 && (prospective[0] < min || prospective[0] > max)) {
00369 continue;
00370 } else if (prospective[1] < min || prospective[0] > max) {
00371 continue;
00372 }
00373
00374 if (++count > n) {
00375 if (i < 11) {
00376 snprintf(next, sizeof(next), "%u", prospective[0]);
00377 } else {
00378 snprintf(next, sizeof(next), "%u...", prospective[0] / 10);
00379 }
00380 return ast_strdup(next);
00381 }
00382 }
00383 return NULL;
00384 }
00385
00386 static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00387 {
00388 int oldval;
00389 int newlevel;
00390 unsigned int is_debug;
00391 int atleast = 0;
00392 int fd = a->fd;
00393 int argc = a->argc;
00394 const char * const *argv = a->argv;
00395 const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
00396 int *dst;
00397 char *what;
00398 struct module_level_list *mll;
00399 struct module_level *ml;
00400
00401 switch (cmd) {
00402 case CLI_INIT:
00403 e->command = "core set {debug|verbose}";
00404 e->usage =
00405 #if !defined(LOW_MEMORY)
00406 "Usage: core set {debug|verbose} [atleast] <level> [module]\n"
00407 #else
00408 "Usage: core set {debug|verbose} [atleast] <level>\n"
00409 #endif
00410 " core set {debug|verbose} off\n"
00411 #if !defined(LOW_MEMORY)
00412 " Sets level of debug or verbose messages to be displayed or\n"
00413 " sets a module name to display debug messages from.\n"
00414 #else
00415 " Sets level of debug or verbose messages to be displayed.\n"
00416 #endif
00417 " 0 or off means no messages should be displayed.\n"
00418 " Equivalent to -d[d[...]] or -v[v[v...]] on startup\n";
00419 return NULL;
00420
00421 case CLI_GENERATE:
00422 if (a->pos == 3 || (a->pos == 4 && !strcasecmp(a->argv[3], "atleast"))) {
00423 const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
00424 int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
00425 if (a->n < 21 && numbermatch == 0) {
00426 return complete_number(pos, 0, 0x7fffffff, a->n);
00427 } else if (pos[0] == '0') {
00428 if (a->n == 0) {
00429 return ast_strdup("0");
00430 } else {
00431 return NULL;
00432 }
00433 } else if (a->n == (21 - numbermatch)) {
00434 if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
00435 return ast_strdup("off");
00436 } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
00437 return ast_strdup("atleast");
00438 }
00439 } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
00440 return ast_strdup("atleast");
00441 }
00442 #if !defined(LOW_MEMORY)
00443 } else if (a->pos == 4 || (a->pos == 5 && !strcasecmp(argv3, "atleast"))) {
00444 return ast_complete_source_filename(a->pos == 4 ? S_OR(a->argv[4], "") : S_OR(a->argv[5], ""), a->n);
00445 #endif
00446 }
00447 return NULL;
00448 }
00449
00450
00451
00452
00453 if (argc <= e->args)
00454 return CLI_SHOWUSAGE;
00455 if (!strcasecmp(argv[e->args - 1], "debug")) {
00456 dst = &option_debug;
00457 oldval = option_debug;
00458 what = "Core debug";
00459 is_debug = 1;
00460 } else {
00461 dst = &option_verbose;
00462 oldval = option_verbose;
00463 what = "Verbosity";
00464 is_debug = 0;
00465 }
00466 if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
00467 newlevel = 0;
00468
00469 mll = is_debug ? &debug_modules : &verbose_modules;
00470
00471 AST_RWLIST_WRLOCK(mll);
00472 while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
00473 ast_free(ml);
00474 }
00475 ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
00476 AST_RWLIST_UNLOCK(mll);
00477
00478 goto done;
00479 }
00480 if (!strcasecmp(argv[e->args], "atleast"))
00481 atleast = 1;
00482 if (argc != e->args + atleast + 1 && argc != e->args + atleast + 2)
00483 return CLI_SHOWUSAGE;
00484 if (sscanf(argv[e->args + atleast], "%30d", &newlevel) != 1)
00485 return CLI_SHOWUSAGE;
00486 if (argc == e->args + atleast + 2) {
00487
00488 char *mod = ast_strdupa(argv[e->args + atleast + 1]);
00489
00490 if ((strlen(mod) > 3) && !strcasecmp(mod + strlen(mod) - 3, ".so")) {
00491 mod[strlen(mod) - 3] = '\0';
00492 }
00493
00494 mll = is_debug ? &debug_modules : &verbose_modules;
00495
00496 AST_RWLIST_WRLOCK(mll);
00497
00498 ml = find_module_level(mod, is_debug);
00499 if (!newlevel) {
00500 if (!ml) {
00501
00502 AST_RWLIST_UNLOCK(mll);
00503 return CLI_SUCCESS;
00504 }
00505 AST_RWLIST_REMOVE(mll, ml, entry);
00506 if (AST_RWLIST_EMPTY(mll))
00507 ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
00508 AST_RWLIST_UNLOCK(mll);
00509 ast_cli(fd, "%s was %d and has been set to 0 for '%s'\n", what, ml->level, mod);
00510 ast_free(ml);
00511 return CLI_SUCCESS;
00512 }
00513
00514 if (ml) {
00515 if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
00516 ast_cli(fd, "%s is %d for '%s'\n", what, ml->level, mod);
00517 AST_RWLIST_UNLOCK(mll);
00518 return CLI_SUCCESS;
00519 }
00520 oldval = ml->level;
00521 ml->level = newlevel;
00522 } else {
00523 ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
00524 if (!ml) {
00525 AST_RWLIST_UNLOCK(mll);
00526 return CLI_FAILURE;
00527 }
00528 oldval = ml->level;
00529 ml->level = newlevel;
00530 strcpy(ml->module, mod);
00531 AST_RWLIST_INSERT_TAIL(mll, ml, entry);
00532 }
00533
00534 ast_set_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
00535
00536 AST_RWLIST_UNLOCK(mll);
00537
00538 ast_cli(fd, "%s was %d and has been set to %d for '%s'\n", what, oldval, ml->level, ml->module);
00539
00540 return CLI_SUCCESS;
00541 } else if (!newlevel) {
00542
00543 mll = is_debug ? &debug_modules : &verbose_modules;
00544
00545 AST_RWLIST_WRLOCK(mll);
00546 while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
00547 ast_free(ml);
00548 }
00549 ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
00550 AST_RWLIST_UNLOCK(mll);
00551 }
00552
00553 done:
00554 if (!atleast || newlevel > *dst)
00555 *dst = newlevel;
00556 if (oldval > 0 && *dst == 0)
00557 ast_cli(fd, "%s is now OFF\n", what);
00558 else if (*dst > 0) {
00559 if (oldval == *dst)
00560 ast_cli(fd, "%s is at least %d\n", what, *dst);
00561 else
00562 ast_cli(fd, "%s was %d and is now %d\n", what, oldval, *dst);
00563 }
00564
00565 return CLI_SUCCESS;
00566 }
00567
00568 static char *handle_logger_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00569 {
00570 switch (cmd) {
00571 case CLI_INIT:
00572 e->command = "logger mute";
00573 e->usage =
00574 "Usage: logger mute\n"
00575 " Disables logging output to the current console, making it possible to\n"
00576 " gather information without being disturbed by scrolling lines.\n";
00577 return NULL;
00578 case CLI_GENERATE:
00579 return NULL;
00580 }
00581
00582 if (a->argc < 2 || a->argc > 3)
00583 return CLI_SHOWUSAGE;
00584
00585 if (a->argc == 3 && !strcasecmp(a->argv[2], "silent"))
00586 ast_console_toggle_mute(a->fd, 1);
00587 else
00588 ast_console_toggle_mute(a->fd, 0);
00589
00590 return CLI_SUCCESS;
00591 }
00592
00593 static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00594 {
00595
00596 int x;
00597 int force = AST_FORCE_SOFT;
00598 const char *s;
00599
00600 switch (cmd) {
00601 case CLI_INIT:
00602 e->command = "module unload";
00603 e->usage =
00604 "Usage: module unload [-f|-h] <module_1> [<module_2> ... ]\n"
00605 " Unloads the specified module from Asterisk. The -f\n"
00606 " option causes the module to be unloaded even if it is\n"
00607 " in use (may cause a crash) and the -h module causes the\n"
00608 " module to be unloaded even if the module says it cannot, \n"
00609 " which almost always will cause a crash.\n";
00610 return NULL;
00611
00612 case CLI_GENERATE:
00613 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
00614 }
00615 if (a->argc < e->args + 1)
00616 return CLI_SHOWUSAGE;
00617 x = e->args;
00618 s = a->argv[x];
00619 if (s[0] == '-') {
00620 if (s[1] == 'f')
00621 force = AST_FORCE_FIRM;
00622 else if (s[1] == 'h')
00623 force = AST_FORCE_HARD;
00624 else
00625 return CLI_SHOWUSAGE;
00626 if (a->argc < e->args + 2)
00627 return CLI_SHOWUSAGE;
00628 x++;
00629 }
00630
00631 for (; x < a->argc; x++) {
00632 if (ast_unload_resource(a->argv[x], force)) {
00633 ast_cli(a->fd, "Unable to unload resource %s\n", a->argv[x]);
00634 return CLI_FAILURE;
00635 }
00636 ast_cli(a->fd, "Unloaded %s\n", a->argv[x]);
00637 }
00638
00639 return CLI_SUCCESS;
00640 }
00641
00642 #define MODLIST_FORMAT "%-30s %-40.40s %-10d\n"
00643 #define MODLIST_FORMAT2 "%-30s %-40.40s %-10s\n"
00644
00645 AST_MUTEX_DEFINE_STATIC(climodentrylock);
00646 static int climodentryfd = -1;
00647
00648 static int modlist_modentry(const char *module, const char *description, int usecnt, const char *like)
00649 {
00650
00651 if (strcasestr(module, like) ) {
00652 ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt);
00653 return 1;
00654 }
00655 return 0;
00656 }
00657
00658 static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
00659 {
00660 int x;
00661 struct ast_str *out;
00662
00663 #define SECOND (1)
00664 #define MINUTE (SECOND*60)
00665 #define HOUR (MINUTE*60)
00666 #define DAY (HOUR*24)
00667 #define WEEK (DAY*7)
00668 #define YEAR (DAY*365)
00669 #define NEEDCOMMA(x) ((x)? ",": "")
00670 if (timeval.tv_sec < 0)
00671 return;
00672
00673 if (printsec) {
00674 ast_cli(fd, "%s: %lu\n", prefix, (u_long)timeval.tv_sec);
00675 return;
00676 }
00677 out = ast_str_alloca(256);
00678 if (timeval.tv_sec > YEAR) {
00679 x = (timeval.tv_sec / YEAR);
00680 timeval.tv_sec -= (x * YEAR);
00681 ast_str_append(&out, 0, "%d year%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
00682 }
00683 if (timeval.tv_sec > WEEK) {
00684 x = (timeval.tv_sec / WEEK);
00685 timeval.tv_sec -= (x * WEEK);
00686 ast_str_append(&out, 0, "%d week%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
00687 }
00688 if (timeval.tv_sec > DAY) {
00689 x = (timeval.tv_sec / DAY);
00690 timeval.tv_sec -= (x * DAY);
00691 ast_str_append(&out, 0, "%d day%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
00692 }
00693 if (timeval.tv_sec > HOUR) {
00694 x = (timeval.tv_sec / HOUR);
00695 timeval.tv_sec -= (x * HOUR);
00696 ast_str_append(&out, 0, "%d hour%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
00697 }
00698 if (timeval.tv_sec > MINUTE) {
00699 x = (timeval.tv_sec / MINUTE);
00700 timeval.tv_sec -= (x * MINUTE);
00701 ast_str_append(&out, 0, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
00702 }
00703 x = timeval.tv_sec;
00704 if (x > 0 || ast_str_strlen(out) == 0)
00705 ast_str_append(&out, 0, "%d second%s ", x, ESS(x));
00706 ast_cli(fd, "%s: %s\n", prefix, ast_str_buffer(out));
00707 }
00708
00709 static struct ast_cli_entry *cli_next(struct ast_cli_entry *e)
00710 {
00711 if (e) {
00712 return AST_LIST_NEXT(e, list);
00713 } else {
00714 return AST_LIST_FIRST(&helpers);
00715 }
00716 }
00717
00718 static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00719 {
00720 struct timeval curtime = ast_tvnow();
00721 int printsec;
00722
00723 switch (cmd) {
00724 case CLI_INIT:
00725 e->command = "core show uptime [seconds]";
00726 e->usage =
00727 "Usage: core show uptime [seconds]\n"
00728 " Shows Asterisk uptime information.\n"
00729 " The seconds word returns the uptime in seconds only.\n";
00730 return NULL;
00731
00732 case CLI_GENERATE:
00733 return NULL;
00734 }
00735
00736 if (a->argc == e->args && !strcasecmp(a->argv[e->args-1],"seconds"))
00737 printsec = 1;
00738 else if (a->argc == e->args-1)
00739 printsec = 0;
00740 else
00741 return CLI_SHOWUSAGE;
00742 if (ast_startuptime.tv_sec)
00743 print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec);
00744 if (ast_lastreloadtime.tv_sec)
00745 print_uptimestr(a->fd, ast_tvsub(curtime, ast_lastreloadtime), "Last reload", printsec);
00746 return CLI_SUCCESS;
00747 }
00748
00749 static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00750 {
00751 const char *like;
00752
00753 switch (cmd) {
00754 case CLI_INIT:
00755 e->command = "module show [like]";
00756 e->usage =
00757 "Usage: module show [like keyword]\n"
00758 " Shows Asterisk modules currently in use, and usage statistics.\n";
00759 return NULL;
00760
00761 case CLI_GENERATE:
00762 if (a->pos == e->args)
00763 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
00764 else
00765 return NULL;
00766 }
00767
00768
00769
00770 if (a->argc == e->args - 1)
00771 like = "";
00772 else if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args-1], "like") )
00773 like = a->argv[e->args];
00774 else
00775 return CLI_SHOWUSAGE;
00776
00777 ast_mutex_lock(&climodentrylock);
00778 climodentryfd = a->fd;
00779 ast_cli(a->fd, MODLIST_FORMAT2, "Module", "Description", "Use Count");
00780 ast_cli(a->fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
00781 climodentryfd = -1;
00782 ast_mutex_unlock(&climodentrylock);
00783 return CLI_SUCCESS;
00784 }
00785 #undef MODLIST_FORMAT
00786 #undef MODLIST_FORMAT2
00787
00788 static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00789 {
00790 struct timeval curtime = ast_tvnow();
00791 int showuptime, printsec;
00792
00793 switch (cmd) {
00794 case CLI_INIT:
00795 e->command = "core show calls [uptime]";
00796 e->usage =
00797 "Usage: core show calls [uptime] [seconds]\n"
00798 " Lists number of currently active calls and total number of calls\n"
00799 " processed through PBX since last restart. If 'uptime' is specified\n"
00800 " the system uptime is also displayed. If 'seconds' is specified in\n"
00801 " addition to 'uptime', the system uptime is displayed in seconds.\n";
00802 return NULL;
00803
00804 case CLI_GENERATE:
00805 if (a->pos != e->args)
00806 return NULL;
00807 return a->n == 0 ? ast_strdup("seconds") : NULL;
00808 }
00809
00810
00811 if (a->argc >= e->args && !strcasecmp(a->argv[e->args-1],"uptime")) {
00812 showuptime = 1;
00813
00814 if (a->argc == e->args+1 && !strcasecmp(a->argv[e->args],"seconds"))
00815 printsec = 1;
00816 else if (a->argc == e->args)
00817 printsec = 0;
00818 else
00819 return CLI_SHOWUSAGE;
00820 } else if (a->argc == e->args-1) {
00821 showuptime = 0;
00822 printsec = 0;
00823 } else
00824 return CLI_SHOWUSAGE;
00825
00826 if (option_maxcalls) {
00827 ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
00828 ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
00829 ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
00830 } else {
00831 ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
00832 }
00833
00834 ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
00835
00836 if (ast_startuptime.tv_sec && showuptime) {
00837 print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec);
00838 }
00839
00840 return RESULT_SUCCESS;
00841 }
00842
00843 static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00844 {
00845 #define FORMAT_STRING "%-20.20s %-20.20s %-7.7s %-30.30s\n"
00846 #define FORMAT_STRING2 "%-20.20s %-20.20s %-7.7s %-30.30s\n"
00847 #define CONCISE_FORMAT_STRING "%s!%s!%s!%d!%s!%s!%s!%s!%s!%s!%d!%s!%s!%s\n"
00848 #define VERBOSE_FORMAT_STRING "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
00849 #define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
00850
00851 struct ast_channel *c = NULL;
00852 int numchans = 0, concise = 0, verbose = 0, count = 0;
00853 struct ast_channel_iterator *iter = NULL;
00854
00855 switch (cmd) {
00856 case CLI_INIT:
00857 e->command = "core show channels [concise|verbose|count]";
00858 e->usage =
00859 "Usage: core show channels [concise|verbose|count]\n"
00860 " Lists currently defined channels and some information about them. If\n"
00861 " 'concise' is specified, the format is abridged and in a more easily\n"
00862 " machine parsable format. If 'verbose' is specified, the output includes\n"
00863 " more and longer fields. If 'count' is specified only the channel and call\n"
00864 " count is output.\n"
00865 " The 'concise' option is deprecated and will be removed from future versions\n"
00866 " of Asterisk.\n";
00867 return NULL;
00868
00869 case CLI_GENERATE:
00870 return NULL;
00871 }
00872
00873 if (a->argc == e->args) {
00874 if (!strcasecmp(a->argv[e->args-1],"concise"))
00875 concise = 1;
00876 else if (!strcasecmp(a->argv[e->args-1],"verbose"))
00877 verbose = 1;
00878 else if (!strcasecmp(a->argv[e->args-1],"count"))
00879 count = 1;
00880 else
00881 return CLI_SHOWUSAGE;
00882 } else if (a->argc != e->args - 1)
00883 return CLI_SHOWUSAGE;
00884
00885 if (!count) {
00886 if (!concise && !verbose)
00887 ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
00888 else if (verbose)
00889 ast_cli(a->fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
00890 "CallerID", "Duration", "Accountcode", "PeerAccount", "BridgedTo");
00891 }
00892
00893 if (!count && !(iter = ast_channel_iterator_all_new())) {
00894 return CLI_FAILURE;
00895 }
00896
00897 for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
00898 struct ast_channel *bc;
00899 char durbuf[10] = "-";
00900
00901 ast_channel_lock(c);
00902
00903 bc = ast_bridged_channel(c);
00904
00905 if (!count) {
00906 if ((concise || verbose) && c->cdr && !ast_tvzero(c->cdr->start)) {
00907 int duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
00908 if (verbose) {
00909 int durh = duration / 3600;
00910 int durm = (duration % 3600) / 60;
00911 int durs = duration % 60;
00912 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
00913 } else {
00914 snprintf(durbuf, sizeof(durbuf), "%d", duration);
00915 }
00916 }
00917 if (concise) {
00918 ast_cli(a->fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
00919 c->appl ? c->appl : "(None)",
00920 S_OR(c->data, ""),
00921 S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""),
00922 S_OR(c->accountcode, ""),
00923 S_OR(c->peeraccount, ""),
00924 c->amaflags,
00925 durbuf,
00926 bc ? bc->name : "(None)",
00927 c->uniqueid);
00928 } else if (verbose) {
00929 ast_cli(a->fd, VERBOSE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
00930 c->appl ? c->appl : "(None)",
00931 c->data ? S_OR(c->data, "(Empty)" ): "(None)",
00932 S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""),
00933 durbuf,
00934 S_OR(c->accountcode, ""),
00935 S_OR(c->peeraccount, ""),
00936 bc ? bc->name : "(None)");
00937 } else {
00938 char locbuf[40] = "(None)";
00939 char appdata[40] = "(None)";
00940
00941 if (!ast_strlen_zero(c->context) && !ast_strlen_zero(c->exten))
00942 snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", c->exten, c->context, c->priority);
00943 if (c->appl)
00944 snprintf(appdata, sizeof(appdata), "%s(%s)", c->appl, S_OR(c->data, ""));
00945 ast_cli(a->fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
00946 }
00947 }
00948 ast_channel_unlock(c);
00949 }
00950
00951 if (iter) {
00952 ast_channel_iterator_destroy(iter);
00953 }
00954
00955 if (!concise) {
00956 numchans = ast_active_channels();
00957 ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
00958 if (option_maxcalls)
00959 ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
00960 ast_active_calls(), option_maxcalls, ESS(ast_active_calls()),
00961 ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
00962 else
00963 ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
00964
00965 ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
00966 }
00967
00968 return CLI_SUCCESS;
00969
00970 #undef FORMAT_STRING
00971 #undef FORMAT_STRING2
00972 #undef CONCISE_FORMAT_STRING
00973 #undef VERBOSE_FORMAT_STRING
00974 #undef VERBOSE_FORMAT_STRING2
00975 }
00976
00977 static char *handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00978 {
00979 struct ast_channel *c=NULL;
00980
00981 switch (cmd) {
00982 case CLI_INIT:
00983 e->command = "channel request hangup";
00984 e->usage =
00985 "Usage: channel request hangup <channel>|<all>\n"
00986 " Request that a channel be hung up. The hangup takes effect\n"
00987 " the next time the driver reads or writes from the channel.\n"
00988 " If 'all' is specified instead of a channel name, all channels\n"
00989 " will see the hangup request.\n";
00990 return NULL;
00991 case CLI_GENERATE:
00992 return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
00993 }
00994
00995 if (a->argc != 4) {
00996 return CLI_SHOWUSAGE;
00997 }
00998
00999 if (!strcasecmp(a->argv[3], "all")) {
01000 struct ast_channel_iterator *iter = NULL;
01001 if (!(iter = ast_channel_iterator_all_new())) {
01002 return CLI_FAILURE;
01003 }
01004 for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
01005 ast_channel_lock(c);
01006 ast_cli(a->fd, "Requested Hangup on channel '%s'\n", c->name);
01007 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
01008 ast_channel_unlock(c);
01009 }
01010 ast_channel_iterator_destroy(iter);
01011 } else if ((c = ast_channel_get_by_name(a->argv[3]))) {
01012 ast_channel_lock(c);
01013 ast_cli(a->fd, "Requested Hangup on channel '%s'\n", c->name);
01014 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT);
01015 ast_channel_unlock(c);
01016 c = ast_channel_unref(c);
01017 } else {
01018 ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
01019 }
01020
01021 return CLI_SUCCESS;
01022 }
01023
01024
01025 static char *handle_cli_show_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01026 {
01027 struct usergroup_cli_perm *cp;
01028 struct cli_perm *perm;
01029 struct passwd *pw = NULL;
01030 struct group *gr = NULL;
01031
01032 switch (cmd) {
01033 case CLI_INIT:
01034 e->command = "cli show permissions";
01035 e->usage =
01036 "Usage: cli show permissions\n"
01037 " Shows CLI configured permissions.\n";
01038 return NULL;
01039 case CLI_GENERATE:
01040 return NULL;
01041 }
01042
01043 AST_RWLIST_RDLOCK(&cli_perms);
01044 AST_LIST_TRAVERSE(&cli_perms, cp, list) {
01045 if (cp->uid >= 0) {
01046 pw = getpwuid(cp->uid);
01047 if (pw) {
01048 ast_cli(a->fd, "user: %s [uid=%d]\n", pw->pw_name, cp->uid);
01049 }
01050 } else {
01051 gr = getgrgid(cp->gid);
01052 if (gr) {
01053 ast_cli(a->fd, "group: %s [gid=%d]\n", gr->gr_name, cp->gid);
01054 }
01055 }
01056 ast_cli(a->fd, "Permissions:\n");
01057 if (cp->perms) {
01058 AST_LIST_TRAVERSE(cp->perms, perm, list) {
01059 ast_cli(a->fd, "\t%s -> %s\n", perm->permit ? "permit" : "deny", perm->command);
01060 }
01061 }
01062 ast_cli(a->fd, "\n");
01063 }
01064 AST_RWLIST_UNLOCK(&cli_perms);
01065
01066 return CLI_SUCCESS;
01067 }
01068
01069
01070 static char *handle_cli_reload_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01071 {
01072 switch (cmd) {
01073 case CLI_INIT:
01074 e->command = "cli reload permissions";
01075 e->usage =
01076 "Usage: cli reload permissions\n"
01077 " Reload the 'cli_permissions.conf' file.\n";
01078 return NULL;
01079 case CLI_GENERATE:
01080 return NULL;
01081 }
01082
01083 ast_cli_perms_init(1);
01084
01085 return CLI_SUCCESS;
01086 }
01087
01088
01089 static char *handle_cli_check_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01090 {
01091 struct passwd *pw = NULL;
01092 struct group *gr;
01093 int gid = -1, uid = -1;
01094 char command[AST_MAX_ARGS] = "";
01095 struct ast_cli_entry *ce = NULL;
01096 int found = 0;
01097 char *group, *tmp;
01098
01099 switch (cmd) {
01100 case CLI_INIT:
01101 e->command = "cli check permissions";
01102 e->usage =
01103 "Usage: cli check permissions {<username>|@<groupname>|<username>@<groupname>} [<command>]\n"
01104 " Check permissions config for a user@group or list the allowed commands for the specified user.\n"
01105 " The username or the groupname may be omitted.\n";
01106 return NULL;
01107 case CLI_GENERATE:
01108 if (a->pos >= 4) {
01109 return ast_cli_generator(a->line + strlen("cli check permissions") + strlen(a->argv[3]) + 1, a->word, a->n);
01110 }
01111 return NULL;
01112 }
01113
01114 if (a->argc < 4) {
01115 return CLI_SHOWUSAGE;
01116 }
01117
01118 tmp = ast_strdupa(a->argv[3]);
01119 group = strchr(tmp, '@');
01120 if (group) {
01121 gr = getgrnam(&group[1]);
01122 if (!gr) {
01123 ast_cli(a->fd, "Unknown group '%s'\n", &group[1]);
01124 return CLI_FAILURE;
01125 }
01126 group[0] = '\0';
01127 gid = gr->gr_gid;
01128 }
01129
01130 if (!group && ast_strlen_zero(tmp)) {
01131 ast_cli(a->fd, "You didn't supply a username\n");
01132 } else if (!ast_strlen_zero(tmp) && !(pw = getpwnam(tmp))) {
01133 ast_cli(a->fd, "Unknown user '%s'\n", tmp);
01134 return CLI_FAILURE;
01135 } else if (pw) {
01136 uid = pw->pw_uid;
01137 }
01138
01139 if (a->argc == 4) {
01140 while ((ce = cli_next(ce))) {
01141
01142 if (ce->_full_cmd[0] == '_') {
01143 continue;
01144 }
01145 if (cli_has_permissions(uid, gid, ce->_full_cmd)) {
01146 ast_cli(a->fd, "%30.30s %s\n", ce->_full_cmd, S_OR(ce->summary, "<no description available>"));
01147 found++;
01148 }
01149 }
01150 if (!found) {
01151 ast_cli(a->fd, "You are not allowed to run any command on Asterisk\n");
01152 }
01153 } else {
01154 ast_join(command, sizeof(command), a->argv + 4);
01155 ast_cli(a->fd, "%s '%s%s%s' is %s to run command: '%s'\n", uid >= 0 ? "User" : "Group", tmp,
01156 group && uid >= 0 ? "@" : "",
01157 group ? &group[1] : "",
01158 cli_has_permissions(uid, gid, command) ? "allowed" : "not allowed", command);
01159 }
01160
01161 return CLI_SUCCESS;
01162 }
01163
01164 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
01165
01166 static char *handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01167 {
01168 char *buf, *obuf;
01169 int buflen = 2048;
01170 int len = 0;
01171 char **matches;
01172 int x, matchlen;
01173
01174 switch (cmd) {
01175 case CLI_INIT:
01176 e->command = "_command matchesarray";
01177 e->usage =
01178 "Usage: _command matchesarray \"<line>\" text \n"
01179 " This function is used internally to help with command completion and should.\n"
01180 " never be called by the user directly.\n";
01181 return NULL;
01182 case CLI_GENERATE:
01183 return NULL;
01184 }
01185
01186 if (a->argc != 4)
01187 return CLI_SHOWUSAGE;
01188 if (!(buf = ast_malloc(buflen)))
01189 return CLI_FAILURE;
01190 buf[len] = '\0';
01191 matches = ast_cli_completion_matches(a->argv[2], a->argv[3]);
01192 if (matches) {
01193 for (x=0; matches[x]; x++) {
01194 matchlen = strlen(matches[x]) + 1;
01195 if (len + matchlen >= buflen) {
01196 buflen += matchlen * 3;
01197 obuf = buf;
01198 if (!(buf = ast_realloc(obuf, buflen)))
01199
01200 ast_free(obuf);
01201 }
01202 if (buf)
01203 len += sprintf( buf + len, "%s ", matches[x]);
01204 ast_free(matches[x]);
01205 matches[x] = NULL;
01206 }
01207 ast_free(matches);
01208 }
01209
01210 if (buf) {
01211 ast_cli(a->fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
01212 ast_free(buf);
01213 } else
01214 ast_cli(a->fd, "NULL\n");
01215
01216 return CLI_SUCCESS;
01217 }
01218
01219
01220
01221 static char *handle_commandnummatches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01222 {
01223 int matches = 0;
01224
01225 switch (cmd) {
01226 case CLI_INIT:
01227 e->command = "_command nummatches";
01228 e->usage =
01229 "Usage: _command nummatches \"<line>\" text \n"
01230 " This function is used internally to help with command completion and should.\n"
01231 " never be called by the user directly.\n";
01232 return NULL;
01233 case CLI_GENERATE:
01234 return NULL;
01235 }
01236
01237 if (a->argc != 4)
01238 return CLI_SHOWUSAGE;
01239
01240 matches = ast_cli_generatornummatches(a->argv[2], a->argv[3]);
01241
01242 ast_cli(a->fd, "%d", matches);
01243
01244 return CLI_SUCCESS;
01245 }
01246
01247 static char *handle_commandcomplete(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01248 {
01249 char *buf;
01250 switch (cmd) {
01251 case CLI_INIT:
01252 e->command = "_command complete";
01253 e->usage =
01254 "Usage: _command complete \"<line>\" text state\n"
01255 " This function is used internally to help with command completion and should.\n"
01256 " never be called by the user directly.\n";
01257 return NULL;
01258 case CLI_GENERATE:
01259 return NULL;
01260 }
01261 if (a->argc != 5)
01262 return CLI_SHOWUSAGE;
01263 buf = __ast_cli_generator(a->argv[2], a->argv[3], atoi(a->argv[4]), 0);
01264 if (buf) {
01265 ast_cli(a->fd, "%s", buf);
01266 ast_free(buf);
01267 } else
01268 ast_cli(a->fd, "NULL\n");
01269 return CLI_SUCCESS;
01270 }
01271
01272 struct channel_set_debug_args {
01273 int fd;
01274 int is_off;
01275 };
01276
01277 static int channel_set_debug(void *obj, void *arg, void *data, int flags)
01278 {
01279 struct ast_channel *chan = obj;
01280 struct channel_set_debug_args *args = data;
01281
01282 ast_channel_lock(chan);
01283
01284 if (!(chan->fin & DEBUGCHAN_FLAG) || !(chan->fout & DEBUGCHAN_FLAG)) {
01285 if (args->is_off) {
01286 chan->fin &= ~DEBUGCHAN_FLAG;
01287 chan->fout &= ~DEBUGCHAN_FLAG;
01288 } else {
01289 chan->fin |= DEBUGCHAN_FLAG;
01290 chan->fout |= DEBUGCHAN_FLAG;
01291 }
01292 ast_cli(args->fd, "Debugging %s on channel %s\n", args->is_off ? "disabled" : "enabled",
01293 chan->name);
01294 }
01295
01296 ast_channel_unlock(chan);
01297
01298 return 0;
01299 }
01300
01301 static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01302 {
01303 struct ast_channel *c = NULL;
01304 struct channel_set_debug_args args = {
01305 .fd = a->fd,
01306 };
01307
01308 switch (cmd) {
01309 case CLI_INIT:
01310 e->command = "core set debug channel";
01311 e->usage =
01312 "Usage: core set debug channel <all|channel> [off]\n"
01313 " Enables/disables debugging on all or on a specific channel.\n";
01314 return NULL;
01315 case CLI_GENERATE:
01316
01317 if (a->pos != e->args)
01318 return NULL;
01319 return a->n == 0 ? ast_strdup("all") : ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args);
01320 }
01321
01322 if (cmd == (CLI_HANDLER + 1000)) {
01323
01324 args.is_off = 1;
01325 } else if (a->argc == e->args + 2) {
01326
01327 if (!strcasecmp(a->argv[e->args + 1], "off"))
01328 args.is_off = 1;
01329 else
01330 return CLI_SHOWUSAGE;
01331 } else if (a->argc != e->args + 1) {
01332 return CLI_SHOWUSAGE;
01333 }
01334
01335 if (!strcasecmp("all", a->argv[e->args])) {
01336 if (args.is_off) {
01337 global_fin &= ~DEBUGCHAN_FLAG;
01338 global_fout &= ~DEBUGCHAN_FLAG;
01339 } else {
01340 global_fin |= DEBUGCHAN_FLAG;
01341 global_fout |= DEBUGCHAN_FLAG;
01342 }
01343 ast_channel_callback(channel_set_debug, NULL, &args, OBJ_NODATA | OBJ_MULTIPLE);
01344 } else {
01345 if ((c = ast_channel_get_by_name(a->argv[e->args]))) {
01346 channel_set_debug(c, NULL, &args, 0);
01347 ast_channel_unref(c);
01348 } else {
01349 ast_cli(a->fd, "No such channel %s\n", a->argv[e->args]);
01350 }
01351 }
01352
01353 ast_cli(a->fd, "Debugging on new channels is %s\n", args.is_off ? "disabled" : "enabled");
01354
01355 return CLI_SUCCESS;
01356 }
01357
01358 static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01359 {
01360 char *res;
01361
01362 switch (cmd) {
01363 case CLI_INIT:
01364 e->command = "no debug channel";
01365 return NULL;
01366 case CLI_HANDLER:
01367
01368 break;
01369 default:
01370 return NULL;
01371 }
01372
01373 if (a->argc != e->args + 1)
01374 return CLI_SHOWUSAGE;
01375
01376
01377
01378
01379
01380 res = handle_core_set_debug_channel(e, CLI_HANDLER + 1000, a);
01381
01382 return res;
01383 }
01384
01385 static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01386 {
01387 struct ast_channel *c=NULL;
01388 struct timeval now;
01389 struct ast_str *out = ast_str_thread_get(&ast_str_thread_global_buf, 16);
01390 char cdrtime[256];
01391 char nf[256], wf[256], rf[256];
01392 struct ast_str *write_transpath = ast_str_alloca(256);
01393 struct ast_str *read_transpath = ast_str_alloca(256);
01394 long elapsed_seconds=0;
01395 int hour=0, min=0, sec=0;
01396 #ifdef CHANNEL_TRACE
01397 int trace_enabled;
01398 #endif
01399
01400 switch (cmd) {
01401 case CLI_INIT:
01402 e->command = "core show channel";
01403 e->usage =
01404 "Usage: core show channel <channel>\n"
01405 " Shows lots of information about the specified channel.\n";
01406 return NULL;
01407 case CLI_GENERATE:
01408 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
01409 }
01410
01411 if (a->argc != 4) {
01412 return CLI_SHOWUSAGE;
01413 }
01414
01415 now = ast_tvnow();
01416
01417 if (!(c = ast_channel_get_by_name(a->argv[3]))) {
01418 ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
01419 return CLI_SUCCESS;
01420 }
01421
01422 ast_channel_lock(c);
01423
01424 if (c->cdr) {
01425 elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
01426 hour = elapsed_seconds / 3600;
01427 min = (elapsed_seconds % 3600) / 60;
01428 sec = elapsed_seconds % 60;
01429 snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
01430 } else {
01431 strcpy(cdrtime, "N/A");
01432 }
01433
01434 ast_cli(a->fd,
01435 " -- General --\n"
01436 " Name: %s\n"
01437 " Type: %s\n"
01438 " UniqueID: %s\n"
01439 " LinkedID: %s\n"
01440 " Caller ID: %s\n"
01441 " Caller ID Name: %s\n"
01442 "Connected Line ID: %s\n"
01443 "Connected Line ID Name: %s\n"
01444 " DNID Digits: %s\n"
01445 " Language: %s\n"
01446 " State: %s (%d)\n"
01447 " Rings: %d\n"
01448 " NativeFormats: %s\n"
01449 " WriteFormat: %s\n"
01450 " ReadFormat: %s\n"
01451 " WriteTranscode: %s %s\n"
01452 " ReadTranscode: %s %s\n"
01453 "1st File Descriptor: %d\n"
01454 " Frames in: %d%s\n"
01455 " Frames out: %d%s\n"
01456 " Time to Hangup: %ld\n"
01457 " Elapsed Time: %s\n"
01458 " Direct Bridge: %s\n"
01459 "Indirect Bridge: %s\n"
01460 " -- PBX --\n"
01461 " Context: %s\n"
01462 " Extension: %s\n"
01463 " Priority: %d\n"
01464 " Call Group: %llu\n"
01465 " Pickup Group: %llu\n"
01466 " Application: %s\n"
01467 " Data: %s\n"
01468 " Blocking in: %s\n",
01469 c->name, c->tech->type, c->uniqueid, c->linkedid,
01470 S_COR(c->caller.id.number.valid, c->caller.id.number.str, "(N/A)"),
01471 S_COR(c->caller.id.name.valid, c->caller.id.name.str, "(N/A)"),
01472 S_COR(c->connected.id.number.valid, c->connected.id.number.str, "(N/A)"),
01473 S_COR(c->connected.id.name.valid, c->connected.id.name.str, "(N/A)"),
01474 S_OR(c->dialed.number.str, "(N/A)"),
01475 c->language,
01476 ast_state2str(c->_state), c->_state, c->rings,
01477 ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
01478 ast_getformatname_multiple(wf, sizeof(wf), c->writeformat),
01479 ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
01480 c->writetrans ? "Yes" : "No",
01481 ast_translate_path_to_str(c->writetrans, &write_transpath),
01482 c->readtrans ? "Yes" : "No",
01483 ast_translate_path_to_str(c->readtrans, &read_transpath),
01484 c->fds[0],
01485 c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
01486 c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
01487 (long)c->whentohangup.tv_sec,
01488 cdrtime, c->_bridge ? c->_bridge->name : "<none>", ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
01489 c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ),
01490 ( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
01491 (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
01492
01493 if (pbx_builtin_serialize_variables(c, &out)) {
01494 ast_cli(a->fd," Variables:\n%s\n", ast_str_buffer(out));
01495 }
01496
01497 if (c->cdr && ast_cdr_serialize_variables(c->cdr, &out, '=', '\n', 1)) {
01498 ast_cli(a->fd," CDR Variables:\n%s\n", ast_str_buffer(out));
01499 }
01500
01501 #ifdef CHANNEL_TRACE
01502 trace_enabled = ast_channel_trace_is_enabled(c);
01503 ast_cli(a->fd, " Context Trace: %s\n", trace_enabled ? "Enabled" : "Disabled");
01504 if (trace_enabled && ast_channel_trace_serialize(c, &out))
01505 ast_cli(a->fd, " Trace:\n%s\n", ast_str_buffer(out));
01506 #endif
01507
01508 ast_channel_unlock(c);
01509 c = ast_channel_unref(c);
01510
01511 return CLI_SUCCESS;
01512 }
01513
01514
01515
01516
01517
01518 char *ast_cli_complete(const char *word, const char * const choices[], int state)
01519 {
01520 int i, which = 0, len;
01521 len = ast_strlen_zero(word) ? 0 : strlen(word);
01522
01523 for (i = 0; choices[i]; i++) {
01524 if ((!len || !strncasecmp(word, choices[i], len)) && ++which > state)
01525 return ast_strdup(choices[i]);
01526 }
01527 return NULL;
01528 }
01529
01530 char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
01531 {
01532 struct ast_channel *c = NULL;
01533 int which = 0;
01534 char notfound = '\0';
01535 char *ret = ¬found;
01536 struct ast_channel_iterator *iter;
01537
01538 if (pos != rpos) {
01539 return NULL;
01540 }
01541
01542 if (ast_strlen_zero(word)) {
01543 iter = ast_channel_iterator_all_new();
01544 } else {
01545 iter = ast_channel_iterator_by_name_new(word, strlen(word));
01546 }
01547
01548 if (!iter) {
01549 return NULL;
01550 }
01551
01552 while (ret == ¬found && (c = ast_channel_iterator_next(iter))) {
01553 if (++which > state) {
01554 ast_channel_lock(c);
01555 ret = ast_strdup(c->name);
01556 ast_channel_unlock(c);
01557 }
01558 ast_channel_unref(c);
01559 }
01560
01561 ast_channel_iterator_destroy(iter);
01562
01563 return ret == ¬found ? NULL : ret;
01564 }
01565
01566 static char *group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01567 {
01568 #define FORMAT_STRING "%-25s %-20s %-20s\n"
01569
01570 struct ast_group_info *gi = NULL;
01571 int numchans = 0;
01572 regex_t regexbuf;
01573 int havepattern = 0;
01574
01575 switch (cmd) {
01576 case CLI_INIT:
01577 e->command = "group show channels";
01578 e->usage =
01579 "Usage: group show channels [pattern]\n"
01580 " Lists all currently active channels with channel group(s) specified.\n"
01581 " Optional regular expression pattern is matched to group names for each\n"
01582 " channel.\n";
01583 return NULL;
01584 case CLI_GENERATE:
01585 return NULL;
01586 }
01587
01588 if (a->argc < 3 || a->argc > 4)
01589 return CLI_SHOWUSAGE;
01590
01591 if (a->argc == 4) {
01592 if (regcomp(®exbuf, a->argv[3], REG_EXTENDED | REG_NOSUB))
01593 return CLI_SHOWUSAGE;
01594 havepattern = 1;
01595 }
01596
01597 ast_cli(a->fd, FORMAT_STRING, "Channel", "Group", "Category");
01598
01599 ast_app_group_list_rdlock();
01600
01601 gi = ast_app_group_list_head();
01602 while (gi) {
01603 if (!havepattern || !regexec(®exbuf, gi->group, 0, NULL, 0)) {
01604 ast_cli(a->fd, FORMAT_STRING, gi->chan->name, gi->group, (ast_strlen_zero(gi->category) ? "(default)" : gi->category));
01605 numchans++;
01606 }
01607 gi = AST_LIST_NEXT(gi, group_list);
01608 }
01609
01610 ast_app_group_list_unlock();
01611
01612 if (havepattern)
01613 regfree(®exbuf);
01614
01615 ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
01616 return CLI_SUCCESS;
01617 #undef FORMAT_STRING
01618 }
01619
01620 static char *handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01621 {
01622 switch (cmd) {
01623 case CLI_INIT:
01624 e->command = "core waitfullybooted";
01625 e->usage =
01626 "Usage: core waitfullybooted\n"
01627 " Wait until Asterisk has fully booted.\n";
01628 return NULL;
01629 case CLI_GENERATE:
01630 return NULL;
01631 }
01632
01633 while (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
01634 usleep(100);
01635 }
01636
01637 ast_cli(a->fd, "Asterisk has fully booted.\n");
01638
01639 return CLI_SUCCESS;
01640 }
01641
01642 static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
01643
01644 static struct ast_cli_entry cli_cli[] = {
01645
01646 AST_CLI_DEFINE(handle_commandcomplete, "Command complete"),
01647 AST_CLI_DEFINE(handle_commandnummatches, "Returns number of command matches"),
01648 AST_CLI_DEFINE(handle_commandmatchesarray, "Returns command matches array"),
01649
01650 AST_CLI_DEFINE(handle_nodebugchan_deprecated, "Disable debugging on channel(s)"),
01651
01652 AST_CLI_DEFINE(handle_chanlist, "Display information on channels"),
01653
01654 AST_CLI_DEFINE(handle_showcalls, "Display information on calls"),
01655
01656 AST_CLI_DEFINE(handle_showchan, "Display information on a specific channel"),
01657
01658 AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
01659
01660 AST_CLI_DEFINE(handle_verbose, "Set level of debug/verbose chattiness"),
01661
01662 AST_CLI_DEFINE(group_show_channels, "Display active channels with group(s)"),
01663
01664 AST_CLI_DEFINE(handle_help, "Display help list, or specific help on a command"),
01665
01666 AST_CLI_DEFINE(handle_logger_mute, "Toggle logging output to a console"),
01667
01668 AST_CLI_DEFINE(handle_modlist, "List modules and info"),
01669
01670 AST_CLI_DEFINE(handle_load, "Load a module by name"),
01671
01672 AST_CLI_DEFINE(handle_reload, "Reload configuration for a module"),
01673
01674 AST_CLI_DEFINE(handle_core_reload, "Global reload"),
01675
01676 AST_CLI_DEFINE(handle_unload, "Unload a module by name"),
01677
01678 AST_CLI_DEFINE(handle_showuptime, "Show uptime information"),
01679
01680 AST_CLI_DEFINE(handle_softhangup, "Request a hangup on a given channel"),
01681
01682 AST_CLI_DEFINE(handle_cli_reload_permissions, "Reload CLI permissions config"),
01683
01684 AST_CLI_DEFINE(handle_cli_show_permissions, "Show CLI permissions"),
01685
01686 AST_CLI_DEFINE(handle_cli_check_permissions, "Try a permissions config for a user"),
01687
01688 AST_CLI_DEFINE(handle_cli_wait_fullybooted, "Wait for Asterisk to be fully booted"),
01689 };
01690
01691
01692
01693
01694 static const char cli_rsvd[] = "[]{}|*%";
01695
01696
01697
01698
01699
01700 static int set_full_cmd(struct ast_cli_entry *e)
01701 {
01702 int i;
01703 char buf[80];
01704
01705 ast_join(buf, sizeof(buf), e->cmda);
01706 e->_full_cmd = ast_strdup(buf);
01707 if (!e->_full_cmd) {
01708 ast_log(LOG_WARNING, "-- cannot allocate <%s>\n", buf);
01709 return -1;
01710 }
01711 e->cmdlen = strcspn(e->_full_cmd, cli_rsvd);
01712 for (i = 0; e->cmda[i]; i++)
01713 ;
01714 e->args = i;
01715 return 0;
01716 }
01717
01718
01719 static void destroy_user_perms(void)
01720 {
01721 struct cli_perm *perm;
01722 struct usergroup_cli_perm *user_perm;
01723
01724 AST_RWLIST_WRLOCK(&cli_perms);
01725 while ((user_perm = AST_LIST_REMOVE_HEAD(&cli_perms, list))) {
01726 while ((perm = AST_LIST_REMOVE_HEAD(user_perm->perms, list))) {
01727 ast_free(perm->command);
01728 ast_free(perm);
01729 }
01730 ast_free(user_perm);
01731 }
01732 AST_RWLIST_UNLOCK(&cli_perms);
01733 }
01734
01735 int ast_cli_perms_init(int reload)
01736 {
01737 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01738 struct ast_config *cfg;
01739 char *cat = NULL;
01740 struct ast_variable *v;
01741 struct usergroup_cli_perm *user_group, *cp_entry;
01742 struct cli_perm *perm = NULL;
01743 struct passwd *pw;
01744 struct group *gr;
01745
01746 if (ast_mutex_trylock(&permsconfiglock)) {
01747 ast_log(LOG_NOTICE, "You must wait until last 'cli reload permissions' command finish\n");
01748 return 1;
01749 }
01750
01751 cfg = ast_config_load2(perms_config, "" , config_flags);
01752 if (!cfg) {
01753 ast_mutex_unlock(&permsconfiglock);
01754 return 1;
01755 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
01756 ast_mutex_unlock(&permsconfiglock);
01757 return 0;
01758 }
01759
01760
01761 destroy_user_perms();
01762
01763 while ((cat = ast_category_browse(cfg, cat))) {
01764 if (!strcasecmp(cat, "general")) {
01765
01766 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
01767 if (!strcasecmp(v->name, "default_perm")) {
01768 cli_default_perm = (!strcasecmp(v->value, "permit")) ? 1: 0;
01769 }
01770 }
01771 continue;
01772 }
01773
01774
01775 gr = NULL, pw = NULL;
01776 if (cat[0] == '@') {
01777
01778 gr = getgrnam(&cat[1]);
01779 if (!gr) {
01780 ast_log (LOG_WARNING, "Unknown group '%s'\n", &cat[1]);
01781 continue;
01782 }
01783 } else {
01784
01785 pw = getpwnam(cat);
01786 if (!pw) {
01787 ast_log (LOG_WARNING, "Unknown user '%s'\n", cat);
01788 continue;
01789 }
01790 }
01791 user_group = NULL;
01792
01793 AST_RWLIST_WRLOCK(&cli_perms);
01794 AST_LIST_TRAVERSE(&cli_perms, cp_entry, list) {
01795 if ((pw && cp_entry->uid == pw->pw_uid) || (gr && cp_entry->gid == gr->gr_gid)) {
01796
01797
01798 user_group = cp_entry;
01799 break;
01800 }
01801 }
01802 AST_RWLIST_UNLOCK(&cli_perms);
01803
01804 if (!user_group) {
01805
01806 user_group = ast_calloc(1, sizeof(*user_group));
01807 if (!user_group) {
01808 continue;
01809 }
01810 user_group->uid = (pw ? pw->pw_uid : -1);
01811 user_group->gid = (gr ? gr->gr_gid : -1);
01812 user_group->perms = ast_calloc(1, sizeof(*user_group->perms));
01813 if (!user_group->perms) {
01814 ast_free(user_group);
01815 continue;
01816 }
01817 }
01818 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
01819 if (ast_strlen_zero(v->value)) {
01820
01821 ast_log(LOG_WARNING, "Empty permit/deny option in user '%s'\n", cat);
01822 continue;
01823 }
01824 if (!strcasecmp(v->name, "permit")) {
01825 perm = ast_calloc(1, sizeof(*perm));
01826 if (perm) {
01827 perm->permit = 1;
01828 perm->command = ast_strdup(v->value);
01829 }
01830 } else if (!strcasecmp(v->name, "deny")) {
01831 perm = ast_calloc(1, sizeof(*perm));
01832 if (perm) {
01833 perm->permit = 0;
01834 perm->command = ast_strdup(v->value);
01835 }
01836 } else {
01837
01838 ast_log(LOG_WARNING, "Unknown '%s' option\n", v->name);
01839 continue;
01840 }
01841 if (perm) {
01842
01843 AST_LIST_INSERT_TAIL(user_group->perms, perm, list);
01844 perm = NULL;
01845 }
01846 }
01847 AST_RWLIST_WRLOCK(&cli_perms);
01848 AST_RWLIST_INSERT_TAIL(&cli_perms, user_group, list);
01849 AST_RWLIST_UNLOCK(&cli_perms);
01850 }
01851
01852 ast_config_destroy(cfg);
01853 ast_mutex_unlock(&permsconfiglock);
01854 return 0;
01855 }
01856
01857
01858 void ast_builtins_init(void)
01859 {
01860 ast_cli_register_multiple(cli_cli, ARRAY_LEN(cli_cli));
01861 }
01862
01863
01864
01865
01866
01867
01868
01869
01870
01871
01872
01873
01874 static int word_match(const char *cmd, const char *cli_word)
01875 {
01876 int l;
01877 char *pos;
01878
01879 if (ast_strlen_zero(cmd) || ast_strlen_zero(cli_word))
01880 return -1;
01881 if (!strchr(cli_rsvd, cli_word[0]))
01882 return (strcasecmp(cmd, cli_word) == 0) ? 1 : -1;
01883 l = strlen(cmd);
01884
01885 if (l > 0 && cli_word[0] == '%') {
01886 return 1;
01887 }
01888
01889
01890 pos = strcasestr(cli_word, cmd);
01891 while (pos) {
01892
01893
01894
01895
01896
01897
01898 if (pos != cli_word && strchr(cli_rsvd, pos[-1]) && strchr(cli_rsvd, pos[l])) {
01899 return 1;
01900 }
01901
01902
01903 pos = strcasestr(pos + 1, cmd);
01904 }
01905
01906 return -1;
01907 }
01908
01909
01910
01911
01912
01913 static char *is_prefix(const char *word, const char *token,
01914 int pos, int *actual)
01915 {
01916 int lw;
01917 char *s, *t1;
01918
01919 *actual = 0;
01920 if (ast_strlen_zero(token))
01921 return NULL;
01922 if (ast_strlen_zero(word))
01923 word = "";
01924 lw = strlen(word);
01925 if (strcspn(word, cli_rsvd) != lw)
01926 return NULL;
01927 if (strchr(cli_rsvd, token[0]) == NULL) {
01928 if (strncasecmp(token, word, lw))
01929 return NULL;
01930 *actual = 1;
01931 return (pos != 0) ? NULL : ast_strdup(token);
01932 }
01933
01934
01935
01936
01937 t1 = ast_strdupa(token + 1);
01938 while (pos >= 0 && (s = strsep(&t1, cli_rsvd)) && *s) {
01939 if (*s == '%')
01940 continue;
01941 if (strncasecmp(s, word, lw))
01942 continue;
01943 (*actual)++;
01944 if (pos-- == 0)
01945 return ast_strdup(s);
01946 }
01947 return NULL;
01948 }
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963 static struct ast_cli_entry *find_cli(const char * const cmds[], int match_type)
01964 {
01965 int matchlen = -1;
01966 struct ast_cli_entry *cand = NULL, *e=NULL;
01967
01968 while ( (e = cli_next(e)) ) {
01969
01970 const char * const *src = cmds;
01971 const char * const *dst = e->cmda;
01972 int n = 0;
01973 for (;; dst++, src += n) {
01974 n = word_match(*src, *dst);
01975 if (n < 0)
01976 break;
01977 }
01978 if (ast_strlen_zero(*dst) || ((*dst)[0] == '[' && ast_strlen_zero(dst[1]))) {
01979
01980 if (ast_strlen_zero(*src))
01981 break;
01982
01983 if (match_type != 0)
01984 continue;
01985
01986 } else {
01987 if (ast_strlen_zero(*src))
01988 continue;
01989
01990
01991
01992
01993 if (match_type != -1 || !ast_strlen_zero(src[1]) ||
01994 !ast_strlen_zero(dst[1]))
01995 continue;
01996
01997 }
01998 if (src - cmds > matchlen) {
01999 matchlen = src - cmds;
02000 cand = e;
02001 }
02002 }
02003
02004 return e ? e : cand;
02005 }
02006
02007 static char *find_best(const char *argv[])
02008 {
02009 static char cmdline[80];
02010 int x;
02011
02012 const char *myargv[AST_MAX_CMD_LEN] = { NULL, };
02013
02014 AST_RWLIST_RDLOCK(&helpers);
02015 for (x = 0; argv[x]; x++) {
02016 myargv[x] = argv[x];
02017 if (!find_cli(myargv, -1))
02018 break;
02019 }
02020 AST_RWLIST_UNLOCK(&helpers);
02021 ast_join(cmdline, sizeof(cmdline), myargv);
02022 return cmdline;
02023 }
02024
02025 static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
02026 {
02027 if (e->inuse) {
02028 ast_log(LOG_WARNING, "Can't remove command that is in use\n");
02029 } else {
02030 AST_RWLIST_WRLOCK(&helpers);
02031 AST_RWLIST_REMOVE(&helpers, e, list);
02032 AST_RWLIST_UNLOCK(&helpers);
02033 ast_free(e->_full_cmd);
02034 e->_full_cmd = NULL;
02035 if (e->handler) {
02036
02037 char *cmda = (char *) e->cmda;
02038 memset(cmda, '\0', sizeof(e->cmda));
02039 ast_free(e->command);
02040 e->command = NULL;
02041 e->usage = NULL;
02042 }
02043 }
02044 return 0;
02045 }
02046
02047 static int __ast_cli_register(struct ast_cli_entry *e, struct ast_cli_entry *ed)
02048 {
02049 struct ast_cli_entry *cur;
02050 int i, lf, ret = -1;
02051
02052 struct ast_cli_args a;
02053 char **dst = (char **)e->cmda;
02054 char *s;
02055
02056 memset(&a, '\0', sizeof(a));
02057 e->handler(e, CLI_INIT, &a);
02058
02059 s = ast_skip_blanks(e->command);
02060 s = e->command = ast_strdup(s);
02061 for (i=0; !ast_strlen_zero(s) && i < AST_MAX_CMD_LEN-1; i++) {
02062 *dst++ = s;
02063 s = ast_skip_nonblanks(s);
02064 if (*s == '\0')
02065 break;
02066 *s++ = '\0';
02067 s = ast_skip_blanks(s);
02068 }
02069 *dst++ = NULL;
02070
02071 AST_RWLIST_WRLOCK(&helpers);
02072
02073 if (find_cli(e->cmda, 1)) {
02074 ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n", S_OR(e->_full_cmd, e->command));
02075 goto done;
02076 }
02077 if (set_full_cmd(e))
02078 goto done;
02079
02080 lf = e->cmdlen;
02081 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&helpers, cur, list) {
02082 int len = cur->cmdlen;
02083 if (lf < len)
02084 len = lf;
02085 if (strncasecmp(e->_full_cmd, cur->_full_cmd, len) < 0) {
02086 AST_RWLIST_INSERT_BEFORE_CURRENT(e, list);
02087 break;
02088 }
02089 }
02090 AST_RWLIST_TRAVERSE_SAFE_END;
02091
02092 if (!cur)
02093 AST_RWLIST_INSERT_TAIL(&helpers, e, list);
02094 ret = 0;
02095
02096 done:
02097 AST_RWLIST_UNLOCK(&helpers);
02098
02099 return ret;
02100 }
02101
02102
02103 int ast_cli_unregister(struct ast_cli_entry *e)
02104 {
02105 return __ast_cli_unregister(e, NULL);
02106 }
02107
02108
02109 int ast_cli_register(struct ast_cli_entry *e)
02110 {
02111 return __ast_cli_register(e, NULL);
02112 }
02113
02114
02115
02116
02117 int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
02118 {
02119 int i, res = 0;
02120
02121 for (i = 0; i < len; i++)
02122 res |= ast_cli_register(e + i);
02123
02124 return res;
02125 }
02126
02127 int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
02128 {
02129 int i, res = 0;
02130
02131 for (i = 0; i < len; i++)
02132 res |= ast_cli_unregister(e + i);
02133
02134 return res;
02135 }
02136
02137
02138
02139
02140
02141 static char *help1(int fd, const char * const match[], int locked)
02142 {
02143 char matchstr[80] = "";
02144 struct ast_cli_entry *e = NULL;
02145 int len = 0;
02146 int found = 0;
02147
02148 if (match) {
02149 ast_join(matchstr, sizeof(matchstr), match);
02150 len = strlen(matchstr);
02151 }
02152 if (!locked)
02153 AST_RWLIST_RDLOCK(&helpers);
02154 while ( (e = cli_next(e)) ) {
02155
02156 if (e->_full_cmd[0] == '_')
02157 continue;
02158 if (match && strncasecmp(matchstr, e->_full_cmd, len))
02159 continue;
02160 ast_cli(fd, "%30.30s %s\n", e->_full_cmd, S_OR(e->summary, "<no description available>"));
02161 found++;
02162 }
02163 if (!locked)
02164 AST_RWLIST_UNLOCK(&helpers);
02165 if (!found && matchstr[0])
02166 ast_cli(fd, "No such command '%s'.\n", matchstr);
02167 return CLI_SUCCESS;
02168 }
02169
02170 static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02171 {
02172 char fullcmd[80];
02173 struct ast_cli_entry *my_e;
02174 char *res = CLI_SUCCESS;
02175
02176 if (cmd == CLI_INIT) {
02177 e->command = "core show help";
02178 e->usage =
02179 "Usage: core show help [topic]\n"
02180 " When called with a topic as an argument, displays usage\n"
02181 " information on the given command. If called without a\n"
02182 " topic, it provides a list of commands.\n";
02183 return NULL;
02184
02185 } else if (cmd == CLI_GENERATE) {
02186
02187 int l = strlen(a->line);
02188
02189 if (l > 15) {
02190 l = 15;
02191 }
02192
02193 return __ast_cli_generator(a->line + l, a->word, a->n, 0);
02194 }
02195 if (a->argc == e->args) {
02196 return help1(a->fd, NULL, 0);
02197 }
02198
02199 AST_RWLIST_RDLOCK(&helpers);
02200 my_e = find_cli(a->argv + 3, 1);
02201 if (!my_e) {
02202 res = help1(a->fd, a->argv + 3, 1 );
02203 AST_RWLIST_UNLOCK(&helpers);
02204 return res;
02205 }
02206 if (my_e->usage)
02207 ast_cli(a->fd, "%s", my_e->usage);
02208 else {
02209 ast_join(fullcmd, sizeof(fullcmd), a->argv + 3);
02210 ast_cli(a->fd, "No help text available for '%s'.\n", fullcmd);
02211 }
02212 AST_RWLIST_UNLOCK(&helpers);
02213 return res;
02214 }
02215
02216 static char *parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
02217 {
02218 char *duplicate, *cur;
02219 int x = 0;
02220 int quoted = 0;
02221 int escaped = 0;
02222 int whitespace = 1;
02223 int dummy = 0;
02224
02225 if (trailingwhitespace == NULL)
02226 trailingwhitespace = &dummy;
02227 *trailingwhitespace = 0;
02228 if (s == NULL)
02229 return NULL;
02230
02231 if (!(duplicate = ast_strdup(s)))
02232 return NULL;
02233
02234 cur = duplicate;
02235
02236 for (; *s ; s++) {
02237 if (x >= max - 1) {
02238 ast_log(LOG_WARNING, "Too many arguments, truncating at %s\n", s);
02239 break;
02240 }
02241 if (*s == '"' && !escaped) {
02242 quoted = !quoted;
02243 if (quoted && whitespace) {
02244
02245 argv[x++] = cur;
02246 whitespace = 0;
02247 }
02248 } else if ((*s == ' ' || *s == '\t') && !(quoted || escaped)) {
02249
02250
02251
02252
02253 if (!whitespace) {
02254 *cur++ = '\0';
02255 whitespace = 1;
02256 }
02257 } else if (*s == '\\' && !escaped) {
02258 escaped = 1;
02259 } else {
02260 if (whitespace) {
02261
02262 argv[x++] = cur;
02263 whitespace = 0;
02264 }
02265 *cur++ = *s;
02266 escaped = 0;
02267 }
02268 }
02269
02270 *cur++ = '\0';
02271
02272
02273
02274
02275 argv[x] = NULL;
02276 *argc = x;
02277 *trailingwhitespace = whitespace;
02278 return duplicate;
02279 }
02280
02281
02282 int ast_cli_generatornummatches(const char *text, const char *word)
02283 {
02284 int matches = 0, i = 0;
02285 char *buf = NULL, *oldbuf = NULL;
02286
02287 while ((buf = ast_cli_generator(text, word, i++))) {
02288 if (!oldbuf || strcmp(buf,oldbuf))
02289 matches++;
02290 if (oldbuf)
02291 ast_free(oldbuf);
02292 oldbuf = buf;
02293 }
02294 if (oldbuf)
02295 ast_free(oldbuf);
02296 return matches;
02297 }
02298
02299 char **ast_cli_completion_matches(const char *text, const char *word)
02300 {
02301 char **match_list = NULL, *retstr, *prevstr;
02302 size_t match_list_len, max_equal, which, i;
02303 int matches = 0;
02304
02305
02306 match_list_len = 1;
02307 while ((retstr = ast_cli_generator(text, word, matches)) != NULL) {
02308 if (matches + 1 >= match_list_len) {
02309 match_list_len <<= 1;
02310 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(*match_list))))
02311 return NULL;
02312 }
02313 match_list[++matches] = retstr;
02314 }
02315
02316 if (!match_list)
02317 return match_list;
02318
02319
02320
02321
02322 prevstr = match_list[1];
02323 max_equal = strlen(prevstr);
02324 for (which = 2; which <= matches; which++) {
02325 for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++)
02326 continue;
02327 max_equal = i;
02328 }
02329
02330 if (!(retstr = ast_malloc(max_equal + 1)))
02331 return NULL;
02332
02333 ast_copy_string(retstr, match_list[1], max_equal + 1);
02334 match_list[0] = retstr;
02335
02336
02337 if (matches + 1 >= match_list_len) {
02338 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(*match_list))))
02339 return NULL;
02340 }
02341 match_list[matches + 1] = NULL;
02342
02343 return match_list;
02344 }
02345
02346
02347 static int more_words (const char * const *dst)
02348 {
02349 int i;
02350 for (i = 0; dst[i]; i++) {
02351 if (dst[i][0] != '[')
02352 return -1;
02353 }
02354 return 0;
02355 }
02356
02357
02358
02359
02360 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock)
02361 {
02362 const char *argv[AST_MAX_ARGS];
02363 struct ast_cli_entry *e = NULL;
02364 int x = 0, argindex, matchlen;
02365 int matchnum=0;
02366 char *ret = NULL;
02367 char matchstr[80] = "";
02368 int tws = 0;
02369
02370 char *duplicate = parse_args(text, &x, argv, ARRAY_LEN(argv), &tws);
02371
02372 if (!duplicate)
02373 return NULL;
02374
02375
02376 argindex = (!ast_strlen_zero(word) && x>0) ? x-1 : x;
02377
02378
02379 ast_join(matchstr, sizeof(matchstr)-1, argv);
02380 matchlen = strlen(matchstr);
02381 if (tws) {
02382 strcat(matchstr, " ");
02383 if (matchlen)
02384 matchlen++;
02385 }
02386 if (lock)
02387 AST_RWLIST_RDLOCK(&helpers);
02388 while ( (e = cli_next(e)) ) {
02389
02390 int src = 0, dst = 0, n = 0;
02391
02392 if (e->command[0] == '_')
02393 continue;
02394
02395
02396
02397
02398
02399 for (;src < argindex; dst++, src += n) {
02400 n = word_match(argv[src], e->cmda[dst]);
02401 if (n < 0)
02402 break;
02403 }
02404
02405 if (src != argindex && more_words(e->cmda + dst))
02406 continue;
02407 ret = is_prefix(argv[src], e->cmda[dst], state - matchnum, &n);
02408 matchnum += n;
02409 if (ret) {
02410
02411
02412
02413
02414 if (matchnum > state)
02415 break;
02416 ast_free(ret);
02417 ret = NULL;
02418 } else if (ast_strlen_zero(e->cmda[dst])) {
02419
02420
02421
02422
02423
02424 if (e->handler) {
02425 struct ast_cli_args a = {
02426 .line = matchstr, .word = word,
02427 .pos = argindex,
02428 .n = state - matchnum,
02429 .argv = argv,
02430 .argc = x};
02431 ret = e->handler(e, CLI_GENERATE, &a);
02432 }
02433 if (ret)
02434 break;
02435 }
02436 }
02437 if (lock)
02438 AST_RWLIST_UNLOCK(&helpers);
02439 ast_free(duplicate);
02440 return ret;
02441 }
02442
02443 char *ast_cli_generator(const char *text, const char *word, int state)
02444 {
02445 return __ast_cli_generator(text, word, state, 1);
02446 }
02447
02448 int ast_cli_command_full(int uid, int gid, int fd, const char *s)
02449 {
02450 const char *args[AST_MAX_ARGS + 1];
02451 struct ast_cli_entry *e;
02452 int x;
02453 char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL);
02454 char tmp[AST_MAX_ARGS + 1];
02455 char *retval = NULL;
02456 struct ast_cli_args a = {
02457 .fd = fd, .argc = x, .argv = args+1 };
02458
02459 if (duplicate == NULL)
02460 return -1;
02461
02462 if (x < 1)
02463 goto done;
02464
02465 AST_RWLIST_RDLOCK(&helpers);
02466 e = find_cli(args + 1, 0);
02467 if (e)
02468 ast_atomic_fetchadd_int(&e->inuse, 1);
02469 AST_RWLIST_UNLOCK(&helpers);
02470 if (e == NULL) {
02471 ast_cli(fd, "No such command '%s' (type 'core show help %s' for other possible commands)\n", s, find_best(args + 1));
02472 goto done;
02473 }
02474
02475 ast_join(tmp, sizeof(tmp), args + 1);
02476
02477 if (!cli_has_permissions(uid, gid, tmp)) {
02478 ast_cli(fd, "You don't have permissions to run '%s' command\n", tmp);
02479 ast_free(duplicate);
02480 return 0;
02481 }
02482
02483
02484
02485
02486
02487 args[0] = (char *)e;
02488
02489 retval = e->handler(e, CLI_HANDLER, &a);
02490
02491 if (retval == CLI_SHOWUSAGE) {
02492 ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
02493 } else {
02494 if (retval == CLI_FAILURE)
02495 ast_cli(fd, "Command '%s' failed.\n", s);
02496 }
02497 ast_atomic_fetchadd_int(&e->inuse, -1);
02498 done:
02499 ast_free(duplicate);
02500 return 0;
02501 }
02502
02503 int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s)
02504 {
02505 char cmd[512];
02506 int x, y = 0, count = 0;
02507
02508 for (x = 0; x < size; x++) {
02509 cmd[y] = s[x];
02510 y++;
02511 if (s[x] == '\0') {
02512 ast_cli_command_full(uid, gid, fd, cmd);
02513 y = 0;
02514 count++;
02515 }
02516 }
02517 return count;
02518 }