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