Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
main/cli.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Standard Command Line Interface
22 *
23 * \author Mark Spencer <markster@digium.com>
24 */
25
26/*! \li \ref cli.c uses the configuration file \ref cli_permissions.conf
27 * \addtogroup configuration_file Configuration Files
28 */
29
30/*!
31 * \page cli_permissions.conf cli_permissions.conf
32 * \verbinclude cli_permissions.conf.sample
33 */
34
35/*** MODULEINFO
36 <support_level>core</support_level>
37 ***/
38
39#include "asterisk.h"
40
41#include "asterisk/_private.h"
42#include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
43#include <signal.h>
44#include <ctype.h>
45#include <regex.h>
46#include <pwd.h>
47#include <grp.h>
48#include <fnmatch.h>
49
50#include "asterisk/cli.h"
52#include "asterisk/module.h"
53#include "asterisk/pbx.h"
54#include "asterisk/channel.h"
55#include "asterisk/utils.h"
56#include "asterisk/app.h"
57#include "asterisk/lock.h"
60#include "asterisk/translate.h"
61#include "asterisk/bridge.h"
64#include "asterisk/vector.h"
65#include "asterisk/stream.h"
66
67/*!
68 * \brief List of restrictions per user.
69 */
70struct cli_perm {
71 unsigned int permit:1; /*!< 1=Permit 0=Deny */
72 char *command; /*!< Command name (to apply restrictions) */
74};
75
77
78/*! \brief list of users to apply restrictions. */
80 int uid; /*!< User ID (-1 disabled) */
81 int gid; /*!< Group ID (-1 disabled) */
82 struct cli_perm_head *perms; /*!< List of permissions. */
83 AST_LIST_ENTRY(usergroup_cli_perm) list;/*!< List mechanics */
84};
85/*! \brief CLI permissions config file. */
86static const char perms_config[] = "cli_permissions.conf";
87/*! \brief Default permissions value 1=Permit 0=Deny */
88static int cli_default_perm = 1;
89
90/*! \brief mutex used to prevent a user from running the 'cli reload permissions' command while
91 * it is already running. */
93/*! \brief List of users and permissions. */
95
96/*!
97 * \brief map a debug or verbose level to a module name
98 */
100 unsigned int level;
102 char module[0];
103};
104
106
107/*! lists of module names and their debug/trace levels */
110
111AST_THREADSTORAGE(ast_cli_buf);
112
115
116/*! \brief Initial buffer size for resulting strings in ast_cli() */
117#define AST_CLI_INITLEN 256
118
119#define MAX_REGEX_ERROR_LEN 128
120
121void ast_cli(int fd, const char *fmt, ...)
122{
123 int res;
124 struct ast_str *buf;
125 va_list ap;
126
127 if (!(buf = ast_str_thread_get(&ast_cli_buf, AST_CLI_INITLEN)))
128 return;
129
130 va_start(ap, fmt);
131 res = ast_str_set_va(&buf, 0, fmt, ap);
132 va_end(ap);
133
134 if (res != AST_DYNSTR_BUILD_FAILED) {
136 }
137}
138
139unsigned int ast_debug_get_by_module(const char *module)
140{
141 struct module_level *ml;
142 unsigned int res = 0;
143
146 if (!strcasecmp(ml->module, module)) {
147 res = ml->level;
148 break;
149 }
150 }
152
153 return res;
154}
155
156unsigned int ast_trace_get_by_module(const char *module)
157{
158 struct module_level *ml;
159 unsigned int res = 0;
160
163 if (!strcasecmp(ml->module, module)) {
164 res = ml->level;
165 break;
166 }
167 }
169
170 return res;
171}
172
173/*! \internal
174 * \brief Check if the user with 'uid' and 'gid' is allow to execute 'command',
175 * if command starts with '_' then not check permissions, just permit
176 * to run the 'command'.
177 * if uid == -1 or gid == -1 do not check permissions.
178 * if uid == -2 and gid == -2 is because rasterisk client didn't send
179 * the credentials, so the cli_default_perm will be applied.
180 * \param uid User ID.
181 * \param gid Group ID.
182 * \param command Command name to check permissions.
183 * \retval 1 if has permission
184 * \retval 0 if it is not allowed.
185 */
186static int cli_has_permissions(int uid, int gid, const char *command)
187{
188 struct usergroup_cli_perm *user_perm;
189 struct cli_perm *perm;
190 /* set to the default permissions general option. */
191 int isallowg = cli_default_perm, isallowu = -1, ispattern;
192 regex_t regexbuf;
193
194 /* if uid == -1 or gid == -1 do not check permissions.
195 if uid == -2 and gid == -2 is because rasterisk client didn't send
196 the credentials, so the cli_default_perm will be applied. */
197 if ((uid == CLI_NO_PERMS && gid == CLI_NO_PERMS) || command[0] == '_') {
198 return 1;
199 }
200
201 if (gid < 0 && uid < 0) {
202 return cli_default_perm;
203 }
204
206 AST_LIST_TRAVERSE(&cli_perms, user_perm, list) {
207 if (user_perm->gid != gid && user_perm->uid != uid) {
208 continue;
209 }
210 AST_LIST_TRAVERSE(user_perm->perms, perm, list) {
211 if (strcasecmp(perm->command, "all") && strncasecmp(perm->command, command, strlen(perm->command))) {
212 /* if the perm->command is a pattern, check it against command. */
213 ispattern = !regcomp(&regexbuf, perm->command, REG_EXTENDED | REG_NOSUB | REG_ICASE);
214 if (ispattern && regexec(&regexbuf, command, 0, NULL, 0)) {
215 regfree(&regexbuf);
216 continue;
217 }
218 if (!ispattern) {
219 continue;
220 }
221 regfree(&regexbuf);
222 }
223 if (user_perm->uid == uid) {
224 /* this is a user definition. */
225 isallowu = perm->permit;
226 } else {
227 /* otherwise is a group definition. */
228 isallowg = perm->permit;
229 }
230 }
231 }
233 if (isallowu > -1) {
234 /* user definition override group definition. */
235 isallowg = isallowu;
236 }
237
238 return isallowg;
239}
240
242
243static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
244{
245 /* "module load <mod>" */
246 switch (cmd) {
247 case CLI_INIT:
248 e->command = "module load";
249 e->usage =
250 "Usage: module load <module name>\n"
251 " Loads the specified module into Asterisk.\n";
252 return NULL;
253
254 case CLI_GENERATE:
255 if (a->pos != e->args) {
256 return NULL;
257 }
258 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_LOAD);
259 }
260 if (a->argc != e->args + 1) {
261 return CLI_SHOWUSAGE;
262 }
263 if (ast_load_resource(a->argv[e->args])) {
264 ast_cli(a->fd, "Unable to load module %s\n", a->argv[e->args]);
265 return CLI_FAILURE;
266 }
267 ast_cli(a->fd, "Loaded %s\n", a->argv[e->args]);
268 return CLI_SUCCESS;
269}
270
271static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
272{
273 int x;
274
275 switch (cmd) {
276 case CLI_INIT:
277 e->command = "module reload";
278 e->usage =
279 "Usage: module reload [module ...]\n"
280 " Reloads configuration files for all listed modules which support\n"
281 " reloading, or for all supported modules if none are listed.\n";
282 return NULL;
283
284 case CLI_GENERATE:
285 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_RELOAD);
286 }
287 if (a->argc == e->args) {
289 return CLI_SUCCESS;
290 }
291 for (x = e->args; x < a->argc; x++) {
292 enum ast_module_reload_result res = ast_module_reload(a->argv[x]);
293 switch (res) {
295 ast_cli(a->fd, "No such module '%s'\n", a->argv[x]);
296 break;
298 ast_cli(a->fd, "The module '%s' does not support reloads\n", a->argv[x]);
299 break;
301 ast_cli(a->fd, "Asterisk cannot reload a module yet; request queued\n");
302 break;
304 ast_cli(a->fd, "The module '%s' reported a reload failure\n", a->argv[x]);
305 break;
307 ast_cli(a->fd, "A module reload request is already in progress; please be patient\n");
308 break;
310 ast_cli(a->fd, "The module '%s' was not properly initialized. Before reloading"
311 " the module, you must run \"module load %s\" and fix whatever is"
312 " preventing the module from being initialized.\n", a->argv[x], a->argv[x]);
313 break;
315 ast_cli(a->fd, "Module '%s' reloaded successfully.\n", a->argv[x]);
316 break;
317 }
318 }
319 return CLI_SUCCESS;
320}
321
322static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
323{
324 switch (cmd) {
325 case CLI_INIT:
326 e->command = "core reload";
327 e->usage =
328 "Usage: core reload\n"
329 " Execute a global reload.\n";
330 return NULL;
331
332 case CLI_GENERATE:
333 return NULL;
334 }
335
336 if (a->argc != e->args) {
337 return CLI_SHOWUSAGE;
338 }
339
341
342 return CLI_SUCCESS;
343}
344
345/*!
346 * \brief Find the module level setting
347 *
348 * \param module Module name to look for.
349 * \param mll List to search.
350 *
351 * \retval level struct found on success.
352 * \retval NULL not found.
353 */
354static struct module_level *find_module_level(const char *module, struct module_level_list *mll)
355{
356 struct module_level *ml;
357
358 AST_LIST_TRAVERSE(mll, ml, entry) {
359 if (!strcasecmp(ml->module, module))
360 return ml;
361 }
362
363 return NULL;
364}
365
366static char *complete_number(const char *partial, unsigned int min, unsigned int max, int n)
367{
368 int i, count = 0;
369 unsigned int prospective[2];
370 unsigned int part = strtoul(partial, NULL, 10);
371 char next[13];
372
373 if (part < min || part > max) {
374 return NULL;
375 }
376
377 for (i = 0; i < 21; i++) {
378 if (i == 0) {
379 prospective[0] = prospective[1] = part;
380 } else if (part == 0 && !ast_strlen_zero(partial)) {
381 break;
382 } else if (i < 11) {
383 prospective[0] = prospective[1] = part * 10 + (i - 1);
384 } else {
385 prospective[0] = (part * 10 + (i - 11)) * 10;
386 prospective[1] = prospective[0] + 9;
387 }
388 if (i < 11 && (prospective[0] < min || prospective[0] > max)) {
389 continue;
390 } else if (prospective[1] < min || prospective[0] > max) {
391 continue;
392 }
393
394 if (++count > n) {
395 if (i < 11) {
396 snprintf(next, sizeof(next), "%u", prospective[0]);
397 } else {
398 snprintf(next, sizeof(next), "%u...", prospective[0] / 10);
399 }
400 return ast_strdup(next);
401 }
402 }
403 return NULL;
404}
405
406#define DEBUG_HANDLER 0
407#define TRACE_HANDLER 1
408#define VERBOSE_HANDLER 2
409
410static void status_debug_verbose(struct ast_cli_args *a, int handler, int old_val, int cur_val)
411{
412 char was_buf[30];
413 const char *was;
414 const char *what = "";
415
416 switch(handler) {
417 case DEBUG_HANDLER:
418 what = "Core debug";
419 break;
420 case TRACE_HANDLER:
421 what = "Core trace";
422 break;
423 case VERBOSE_HANDLER:
424 what = "Console verbose";
425 break;
426 }
427
428 if (old_val) {
429 snprintf(was_buf, sizeof(was_buf), "%d", old_val);
430 was = was_buf;
431 } else {
432 was = "OFF";
433 }
434
435 if (old_val == cur_val) {
436 ast_cli(a->fd, "%s is still %s.\n", what, was);
437 } else {
438 char now_buf[30];
439 const char *now;
440
441 if (cur_val) {
442 snprintf(now_buf, sizeof(now_buf), "%d", cur_val);
443 now = now_buf;
444 } else {
445 now = "OFF";
446 }
447
448 ast_cli(a->fd, "%s was %s and is now %s.\n", what, was, now);
449 }
450}
451
452static char *handle_debug_or_trace(int handler, struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
453{
454 int oldval;
455 int newlevel;
456 int atleast = 0;
457 struct module_level *ml;
458 struct module_level_list *modules;
459 unsigned int module_option;
460 int *core_option;
461 const char *handler_name;
462
463 if (a->argc <= e->args) {
464 return CLI_SHOWUSAGE;
465 }
466
467 if (handler == DEBUG_HANDLER) {
468 modules = &debug_modules;
469 module_option = AST_OPT_FLAG_DEBUG_MODULE;
470 core_option = &option_debug;
471 handler_name = "debug";
472 } else {
473 modules = &trace_modules;
474 module_option = AST_OPT_FLAG_TRACE_MODULE;
475 core_option = &option_trace;
476 handler_name = "trace";
477 }
478
479 if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {
480 newlevel = 0;
481 } else {
482 if (!strcasecmp(a->argv[e->args], "atleast")) {
483 atleast = 1;
484 }
485
486 if (a->argc != e->args + atleast + 1 && a->argc != e->args + atleast + 2) {
487 return CLI_SHOWUSAGE;
488 }
489
490 if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
491 return CLI_SHOWUSAGE;
492 }
493
494 if (a->argc == e->args + atleast + 2) {
495 /* We have specified a module name. */
496 char *mod = ast_strdupa(a->argv[e->args + atleast + 1]);
497 int mod_len = strlen(mod);
498
499 if (3 < mod_len && !strcasecmp(mod + mod_len - 3, ".so")) {
500 mod[mod_len - 3] = '\0';
501 }
502
503 AST_RWLIST_WRLOCK(modules);
504
505 ml = find_module_level(mod, modules);
506 if (!newlevel) {
507 if (!ml) {
508 /* Specified off for a nonexistent entry. */
509 AST_RWLIST_UNLOCK(modules);
510 ast_cli(a->fd, "Core %s is still 0 for '%s'.\n", handler_name, mod);
511 return CLI_SUCCESS;
512 }
513 AST_RWLIST_REMOVE(modules, ml, entry);
514 if (AST_RWLIST_EMPTY(modules)) {
515 ast_clear_flag64(&ast_options, module_option);
516 }
517 AST_RWLIST_UNLOCK(modules);
518 ast_cli(a->fd, "Core %s was %u and has been set to 0 for '%s'.\n", handler_name,
519 ml->level, mod);
520 ast_free(ml);
521 return CLI_SUCCESS;
522 }
523
524 if (ml) {
525 if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
526 ast_cli(a->fd, "Core %s is still %u for '%s'.\n", handler_name, ml->level, mod);
527 AST_RWLIST_UNLOCK(modules);
528 return CLI_SUCCESS;
529 }
530 oldval = ml->level;
531 ml->level = newlevel;
532 } else {
533 ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
534 if (!ml) {
535 AST_RWLIST_UNLOCK(modules);
536 return CLI_FAILURE;
537 }
538 oldval = ml->level;
539 ml->level = newlevel;
540 strcpy(ml->module, mod);
541 AST_RWLIST_INSERT_TAIL(modules, ml, entry);
542 }
543 ast_set_flag64(&ast_options, module_option);
544
545 ast_cli(a->fd, "Core %s was %d and has been set to %u for '%s'.\n", handler_name,
546 oldval, ml->level, ml->module);
547
548 AST_RWLIST_UNLOCK(modules);
549
550 return CLI_SUCCESS;
551 }
552 }
553
554 /* Update global debug level */
555 if (!newlevel) {
556 /* Specified level was 0 or off. */
557 AST_RWLIST_WRLOCK(modules);
558 while ((ml = AST_RWLIST_REMOVE_HEAD(modules, entry))) {
559 ast_free(ml);
560 }
562 AST_RWLIST_UNLOCK(modules);
563 }
564 oldval = *core_option;
565 if (!atleast || newlevel > *core_option) {
566 *core_option = newlevel;
567 }
568
569 /* Report debug level status */
570 status_debug_verbose(a, handler, oldval, *core_option);
571
572 return CLI_SUCCESS;
573}
574
575static char *handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
576{
577 int atleast = 0;
578 const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
579
580 switch (cmd) {
581 case CLI_INIT:
582 e->command = "core set debug";
583 e->usage =
584 "Usage: core set debug [atleast] <level> [module]\n"
585 " core set debug off\n"
586 "\n"
587 " Sets level of debug messages to be displayed or\n"
588 " sets a module name to display debug messages from.\n"
589 " 0 or off means no messages should be displayed.\n"
590 " Equivalent to -d[d[...]] on startup\n";
591 return NULL;
592
593 case CLI_GENERATE:
594 if (!strcasecmp(argv3, "category")) {
595 return NULL;
596 }
597
598 if (!strcasecmp(argv3, "atleast")) {
599 atleast = 1;
600 }
601 if (a->pos == 3 || (a->pos == 4 && atleast)) {
602 const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
603 int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
604
605 if (a->n < 21 && numbermatch == 0) {
606 return complete_number(pos, 0, 0x7fffffff, a->n);
607 } else if (pos[0] == '0') {
608 if (a->n == 0) {
609 return ast_strdup("0");
610 }
611 } else if (a->n == (21 - numbermatch)) {
612 if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
613 return ast_strdup("off");
614 } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
615 return ast_strdup("atleast");
616 }
617 } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
618 return ast_strdup("atleast");
619 }
620 } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off") && strcasecmp(argv3, "channel"))
621 || (a->pos == 5 && atleast)) {
622 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_RUNNING);
623 }
624 return NULL;
625 }
626 /* all the above return, so we proceed with the handler.
627 * we are guaranteed to be called with argc >= e->args;
628 */
629
630 return handle_debug_or_trace(DEBUG_HANDLER, e, cmd, a);
631}
632
633static char *handle_trace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
634{
635 int atleast = 0;
636 const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
637
638 switch (cmd) {
639 case CLI_INIT:
640 e->command = "core set trace";
641 e->usage =
642 "Usage: core set trace [atleast] <level> [module]\n"
643 " core set trace off\n"
644 "\n"
645 " Sets level of trace messages to be displayed or\n"
646 " sets a module name to display trace messages from.\n"
647 " 0 or off means no messages should be displayed.\n";
648 return NULL;
649
650 case CLI_GENERATE:
651 if (!strcasecmp(argv3, "atleast")) {
652 atleast = 1;
653 }
654 if (a->pos == 3 || (a->pos == 4 && atleast)) {
655 const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
656 int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
657
658 if (a->n < 21 && numbermatch == 0) {
659 return complete_number(pos, 0, 0x7fffffff, a->n);
660 } else if (pos[0] == '0') {
661 if (a->n == 0) {
662 return ast_strdup("0");
663 }
664 } else if (a->n == (21 - numbermatch)) {
665 if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
666 return ast_strdup("off");
667 } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
668 return ast_strdup("atleast");
669 }
670 } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
671 return ast_strdup("atleast");
672 }
673 } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off") && strcasecmp(argv3, "channel"))
674 || (a->pos == 5 && atleast)) {
675 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_RUNNING);
676 }
677 return NULL;
678 }
679 /* all the above return, so we proceed with the handler.
680 * we are guaranteed to be called with argc >= e->args;
681 */
682
683 return handle_debug_or_trace(TRACE_HANDLER, e, cmd, a);
684}
685
686static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
687{
688 int oldval;
689 int newlevel;
690 int atleast = 0;
691 int silent = 0;
692 const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
693
694 switch (cmd) {
695 case CLI_INIT:
696 e->command = "core set verbose";
697 e->usage =
698 "Usage: core set verbose [atleast] <level> [silent]\n"
699 " core set verbose off\n"
700 "\n"
701 " Sets level of verbose messages to be displayed.\n"
702 " 0 or off means no verbose messages should be displayed.\n"
703 " The silent option means the command does not report what\n"
704 " happened to the verbose level.\n"
705 " Equivalent to -v[v[...]] on startup\n";
706 return NULL;
707
708 case CLI_GENERATE:
709 if (!strcasecmp(argv3, "atleast")) {
710 atleast = 1;
711 }
712 if (a->pos == 3 || (a->pos == 4 && atleast)) {
713 const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
714 int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
715
716 if (a->n < 21 && numbermatch == 0) {
717 return complete_number(pos, 0, 0x7fffffff, a->n);
718 } else if (pos[0] == '0') {
719 if (a->n == 0) {
720 return ast_strdup("0");
721 }
722 } else if (a->n == (21 - numbermatch)) {
723 if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
724 return ast_strdup("off");
725 } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
726 return ast_strdup("atleast");
727 }
728 } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
729 return ast_strdup("atleast");
730 }
731 } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off"))
732 || (a->pos == 5 && atleast)) {
733 const char *pos = S_OR(a->argv[a->pos], "");
734
735 if (a->n == 0 && !strncasecmp(pos, "silent", strlen(pos))) {
736 return ast_strdup("silent");
737 }
738 }
739 return NULL;
740 }
741 /* all the above return, so we proceed with the handler.
742 * we are guaranteed to be called with argc >= e->args;
743 */
744
745 if (a->argc <= e->args) {
746 return CLI_SHOWUSAGE;
747 }
748
749 if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {
750 newlevel = 0;
751 } else {
752 if (!strcasecmp(a->argv[e->args], "atleast")) {
753 atleast = 1;
754 }
755 if (a->argc == e->args + atleast + 2
756 && !strcasecmp(a->argv[e->args + atleast + 1], "silent")) {
757 silent = 1;
758 }
759 if (a->argc != e->args + atleast + silent + 1) {
760 return CLI_SHOWUSAGE;
761 }
762 if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
763 return CLI_SHOWUSAGE;
764 }
765 }
766
767 /* Update verbose level */
768 oldval = ast_verb_console_get();
769 if (!atleast || newlevel > oldval) {
770 ast_verb_console_set(newlevel);
771 } else {
772 newlevel = oldval;
773 }
774
775 if (silent) {
776 /* Be silent after setting the level. */
777 return CLI_SUCCESS;
778 }
779
780 /* Report verbose level status */
781 status_debug_verbose(a, VERBOSE_HANDLER, oldval, newlevel);
782
783 return CLI_SUCCESS;
784}
785
786static char *handle_logger_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
787{
788 switch (cmd) {
789 case CLI_INIT:
790 e->command = "logger mute";
791 e->usage =
792 "Usage: logger mute\n"
793 " Disables logging output to the current console, making it possible to\n"
794 " gather information without being disturbed by scrolling lines.\n";
795 return NULL;
796 case CLI_GENERATE:
797 return NULL;
798 }
799
800 if (a->argc < 2 || a->argc > 3)
801 return CLI_SHOWUSAGE;
802
803 if (a->argc == 3 && !strcasecmp(a->argv[2], "silent"))
805 else
807
808 return CLI_SUCCESS;
809}
810
811static char *handle_refresh(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
812{
813 static const char * const completions[] = { "recursively", NULL };
814 int res;
815 /* "module refresh <mod>" */
816 switch (cmd) {
817 case CLI_INIT:
818 e->command = "module refresh";
819 e->usage =
820 "Usage: module refresh <module name> [recursively]\n"
821 " Unloads and loads the specified module into Asterisk.\n"
822 " 'recursively' will attempt to unload any modules with\n"
823 " dependencies on this module for you and load them again\n"
824 " afterwards.\n";
825 return NULL;
826
827 case CLI_GENERATE:
828 if (a->pos == e->args) {
829 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_UNLOAD);
830 } else if (a->pos == e->args + 1) {
831 return ast_cli_complete(a->word, completions, a->n);
832 }
833 return NULL;
834 }
835 if (a->argc < 3 || a->argc > 4) {
836 return CLI_SHOWUSAGE;
837 }
838
839 res = ast_refresh_resource(a->argv[e->args], AST_FORCE_SOFT, a->argc == 4 && !strcasecmp(a->argv[3], "recursively"));
840 if (res) {
841 ast_cli(a->fd, "Unable to %s resource %s\n", res > 0 ? "unload" : "load", a->argv[e->args]);
842 return CLI_FAILURE;
843 }
844 ast_cli(a->fd, "Unloaded and loaded %s\n", a->argv[e->args]);
845 return CLI_SUCCESS;
846}
847
848static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
849{
850 /* "module unload mod_1 [mod_2 .. mod_N]" */
851 int x;
852 int force = AST_FORCE_SOFT;
853 const char *s;
854
855 switch (cmd) {
856 case CLI_INIT:
857 e->command = "module unload";
858 e->usage =
859 "Usage: module unload [-f|-h] <module_1> [<module_2> ... ]\n"
860 " Unloads the specified module from Asterisk. The -f\n"
861 " option causes the module to be unloaded even if it is\n"
862 " in use (may cause a crash) and the -h module causes the\n"
863 " module to be unloaded even if the module says it cannot, \n"
864 " which almost always will cause a crash.\n";
865 return NULL;
866
867 case CLI_GENERATE:
868 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_UNLOAD);
869 }
870 if (a->argc < e->args + 1)
871 return CLI_SHOWUSAGE;
872 x = e->args; /* first argument */
873 s = a->argv[x];
874 if (s[0] == '-') {
875 if (s[1] == 'f')
876 force = AST_FORCE_FIRM;
877 else if (s[1] == 'h')
878 force = AST_FORCE_HARD;
879 else
880 return CLI_SHOWUSAGE;
881 if (a->argc < e->args + 2) /* need at least one module name */
882 return CLI_SHOWUSAGE;
883 x++; /* skip this argument */
884 }
885
886 for (; x < a->argc; x++) {
887 if (ast_unload_resource(a->argv[x], force)) {
888 ast_cli(a->fd, "Unable to unload resource %s\n", a->argv[x]);
889 return CLI_FAILURE;
890 }
891 ast_cli(a->fd, "Unloaded %s\n", a->argv[x]);
892 }
893
894 return CLI_SUCCESS;
895}
896
897#define MODLIST_FORMAT "%-30s %-40.40s %-10d %-11s %13s\n"
898#define MODLIST_FORMAT2 "%-30s %-40.40s %-10s %-11s %13s\n"
899
901static int climodentryfd = -1;
902
903static int modlist_modentry(const char *module, const char *description,
904 int usecnt, const char *status, const char *like,
905 enum ast_module_support_level support_level)
906{
907 /* Comparing the like with the module */
908 if (strcasestr(module, like) ) {
909 ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt,
911 return 1;
912 }
913 return 0;
914}
915
916static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
917{
918 int x; /* the main part - years, weeks, etc. */
919 struct ast_str *out;
920
921#define SECOND (1)
922#define MINUTE (SECOND*60)
923#define HOUR (MINUTE*60)
924#define DAY (HOUR*24)
925#define WEEK (DAY*7)
926#define YEAR (DAY*365)
927#define NEEDCOMMA(x) ((x) ? ", " : "") /* define if we need a comma */
928 if (timeval.tv_sec < 0) /* invalid, nothing to show */
929 return;
930
931 if (printsec) { /* plain seconds output */
932 ast_cli(fd, "%s%lu\n", prefix, (u_long)timeval.tv_sec);
933 return;
934 }
935 out = ast_str_alloca(256);
936 if (timeval.tv_sec > YEAR) {
937 x = (timeval.tv_sec / YEAR);
938 timeval.tv_sec -= (x * YEAR);
939 ast_str_append(&out, 0, "%d year%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
940 }
941 if (timeval.tv_sec > WEEK) {
942 x = (timeval.tv_sec / WEEK);
943 timeval.tv_sec -= (x * WEEK);
944 ast_str_append(&out, 0, "%d week%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
945 }
946 if (timeval.tv_sec > DAY) {
947 x = (timeval.tv_sec / DAY);
948 timeval.tv_sec -= (x * DAY);
949 ast_str_append(&out, 0, "%d day%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
950 }
951 if (timeval.tv_sec > HOUR) {
952 x = (timeval.tv_sec / HOUR);
953 timeval.tv_sec -= (x * HOUR);
954 ast_str_append(&out, 0, "%d hour%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
955 }
956 if (timeval.tv_sec > MINUTE) {
957 x = (timeval.tv_sec / MINUTE);
958 timeval.tv_sec -= (x * MINUTE);
959 ast_str_append(&out, 0, "%d minute%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
960 }
961 x = timeval.tv_sec;
962 if (x > 0 || ast_str_strlen(out) == 0) {
963 /* if there is nothing, print 0 seconds */
964 ast_str_append(&out, 0, "%d second%s", x, ESS(x));
965 }
966 ast_cli(fd, "%s%s\n", prefix, ast_str_buffer(out));
967}
968
969static struct ast_cli_entry *cli_next(struct ast_cli_entry *e)
970{
971 if (e) {
972 return AST_LIST_NEXT(e, list);
973 } else {
974 return AST_LIST_FIRST(&helpers);
975 }
976}
977
978static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
979{
980 struct timeval curtime = ast_tvnow();
981 int printsec;
982
983 switch (cmd) {
984 case CLI_INIT:
985 e->command = "core show uptime [seconds]";
986 e->usage =
987 "Usage: core show uptime [seconds]\n"
988 " Shows Asterisk uptime information.\n"
989 " The seconds word returns the uptime in seconds only.\n";
990 return NULL;
991
992 case CLI_GENERATE:
993 return NULL;
994 }
995 /* regular handler */
996 if (a->argc == e->args && !strcasecmp(a->argv[e->args-1],"seconds"))
997 printsec = 1;
998 else if (a->argc == e->args-1)
999 printsec = 0;
1000 else
1001 return CLI_SHOWUSAGE;
1002 if (ast_startuptime.tv_sec) {
1003 print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime: ", printsec);
1004 }
1005 if (ast_lastreloadtime.tv_sec) {
1006 print_uptimestr(a->fd, ast_tvsub(curtime, ast_lastreloadtime), "Last reload: ", printsec);
1007 }
1008 return CLI_SUCCESS;
1009}
1010
1011static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1012{
1013 const char *like;
1014
1015 switch (cmd) {
1016 case CLI_INIT:
1017 e->command = "module show [like]";
1018 e->usage =
1019 "Usage: module show [like keyword]\n"
1020 " Shows Asterisk modules currently in use, and usage statistics.\n";
1021 return NULL;
1022
1023 case CLI_GENERATE:
1024 if (a->pos == e->args) {
1025 return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_LOADED);
1026 } else {
1027 return NULL;
1028 }
1029 }
1030 /* all the above return, so we proceed with the handler.
1031 * we are guaranteed to have argc >= e->args
1032 */
1033 if (a->argc == e->args - 1)
1034 like = "";
1035 else if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args-1], "like") )
1036 like = a->argv[e->args];
1037 else
1038 return CLI_SHOWUSAGE;
1039
1041 climodentryfd = a->fd; /* global, protected by climodentrylock */
1042 ast_cli(a->fd, MODLIST_FORMAT2, "Module", "Description", "Use Count", "Status", "Support Level");
1043 ast_cli(a->fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
1044 climodentryfd = -1;
1046 return CLI_SUCCESS;
1047}
1048#undef MODLIST_FORMAT
1049#undef MODLIST_FORMAT2
1050
1051static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1052{
1053 static const char * const completions[] = { "seconds", NULL };
1054 struct timeval curtime = ast_tvnow();
1055 int showuptime, printsec;
1056
1057 switch (cmd) {
1058 case CLI_INIT:
1059 e->command = "core show calls [uptime]";
1060 e->usage =
1061 "Usage: core show calls [uptime [seconds]]\n"
1062 " Lists number of currently active calls and total number of calls\n"
1063 " processed through PBX since last restart. If 'uptime' is specified\n"
1064 " the system uptime is also displayed. If 'seconds' is specified in\n"
1065 " addition to 'uptime', the system uptime is displayed in seconds.\n";
1066 return NULL;
1067
1068 case CLI_GENERATE:
1069 if (a->pos != e->args)
1070 return NULL;
1071 return ast_cli_complete(a->word, completions, a->n);
1072 }
1073
1074 /* regular handler */
1075 if (a->argc >= e->args && !strcasecmp(a->argv[e->args-1],"uptime")) {
1076 showuptime = 1;
1077
1078 if (a->argc == e->args+1 && !strcasecmp(a->argv[e->args],"seconds"))
1079 printsec = 1;
1080 else if (a->argc == e->args)
1081 printsec = 0;
1082 else
1083 return CLI_SHOWUSAGE;
1084 } else if (a->argc == e->args-1) {
1085 showuptime = 0;
1086 printsec = 0;
1087 } else
1088 return CLI_SHOWUSAGE;
1089
1090 if (ast_option_maxcalls) {
1091 ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
1093 ((double)ast_active_calls() / (double)ast_option_maxcalls) * 100.0);
1094 } else {
1095 ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
1096 }
1097
1098 ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
1099
1100 if (ast_startuptime.tv_sec && showuptime) {
1101 print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime: ", printsec);
1102 }
1103
1104 return RESULT_SUCCESS;
1105}
1106
1107static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1108{
1109#define FORMAT_STRING "%-64.64s %-32.32s %-7.7s %-30.30s\n"
1110#define FORMAT_STRING2 "%-64.64s %-32.32s %-7.7s %-30.30s\n"
1111#define CONCISE_FORMAT_STRING "%s!%s!%s!%d!%s!%s!%s!%s!%s!%s!%d!%s!%s!%s\n"
1112#define VERBOSE_FORMAT_STRING "%-80.80s %-24.24s %-24.24s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
1113#define VERBOSE_FORMAT_STRING2 "%-80.80s %-24.24s %-24.24s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
1114
1115 struct ao2_container *channels;
1116 struct ao2_iterator it_chans;
1117 struct ast_channel_snapshot *cs;
1118 int numchans = 0, concise = 0, verbose = 0, count = 0;
1119
1120 switch (cmd) {
1121 case CLI_INIT:
1122 e->command = "core show channels [concise|verbose|count]";
1123 e->usage =
1124 "Usage: core show channels [concise|verbose|count]\n"
1125 " Lists currently defined channels and some information about them. If\n"
1126 " 'concise' is specified, the format is abridged and in a more easily\n"
1127 " machine parsable format. If 'verbose' is specified, the output includes\n"
1128 " more and longer fields. If 'count' is specified only the channel and call\n"
1129 " count is output.\n";
1130 return NULL;
1131
1132 case CLI_GENERATE:
1133 return NULL;
1134 }
1135
1136 if (a->argc == e->args) {
1137 if (!strcasecmp(a->argv[e->args-1],"concise"))
1138 concise = 1;
1139 else if (!strcasecmp(a->argv[e->args-1],"verbose"))
1140 verbose = 1;
1141 else if (!strcasecmp(a->argv[e->args-1],"count"))
1142 count = 1;
1143 else
1144 return CLI_SHOWUSAGE;
1145 } else if (a->argc != e->args - 1)
1146 return CLI_SHOWUSAGE;
1147
1149
1150 if (!count) {
1151 if (!concise && !verbose)
1152 ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
1153 else if (verbose)
1154 ast_cli(a->fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
1155 "CallerID", "Duration", "Accountcode", "PeerAccount", "BridgeID");
1156 }
1157
1158 it_chans = ao2_iterator_init(channels, 0);
1159 for (; (cs = ao2_iterator_next(&it_chans)); ao2_ref(cs, -1)) {
1160 char durbuf[16] = "-";
1161
1162 if (!count) {
1163 if ((concise || verbose) && !ast_tvzero(cs->base->creationtime)) {
1164 int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
1165 if (verbose) {
1166 int durh = duration / 3600;
1167 int durm = (duration % 3600) / 60;
1168 int durs = duration % 60;
1169 snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
1170 } else {
1171 snprintf(durbuf, sizeof(durbuf), "%d", duration);
1172 }
1173 }
1174 if (concise) {
1176 S_OR(cs->dialplan->appl, "(None)"),
1177 cs->dialplan->data,
1178 cs->caller->number,
1179 cs->base->accountcode,
1180 cs->peer->account,
1181 cs->amaflags,
1182 durbuf,
1183 cs->bridge->id,
1184 cs->base->uniqueid);
1185 } else if (verbose) {
1187 S_OR(cs->dialplan->appl, "(None)"),
1188 S_OR(cs->dialplan->data, "(Empty)"),
1189 cs->caller->number,
1190 durbuf,
1191 cs->base->accountcode,
1192 cs->peer->account,
1193 cs->bridge->id);
1194 } else {
1195 char locbuf[40] = "(None)";
1196 char appdata[40] = "(None)";
1197
1199 snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->dialplan->exten, cs->dialplan->context, cs->dialplan->priority);
1200 }
1201 if (!ast_strlen_zero(cs->dialplan->appl)) {
1202 snprintf(appdata, sizeof(appdata), "%s(%s)", cs->dialplan->appl, S_OR(cs->dialplan->data, ""));
1203 }
1204 ast_cli(a->fd, FORMAT_STRING, cs->base->name, locbuf, ast_state2str(cs->state), appdata);
1205 }
1206 }
1207 }
1208 ao2_iterator_destroy(&it_chans);
1209
1210 if (!concise) {
1211 numchans = ast_active_channels();
1212 ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
1214 ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
1216 ((double)ast_active_calls() / (double)ast_option_maxcalls) * 100.0);
1217 else
1218 ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
1219
1220 ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
1221 }
1222 ao2_ref(channels, -1);
1223
1224 return CLI_SUCCESS;
1225
1226#undef FORMAT_STRING
1227#undef FORMAT_STRING2
1228#undef CONCISE_FORMAT_STRING
1229#undef VERBOSE_FORMAT_STRING
1230#undef VERBOSE_FORMAT_STRING2
1231}
1232
1233static int channel_match_by_regex(const char *channel_name, const void *data)
1234{
1235 return regexec(data, channel_name, 0, NULL, 0);
1236}
1237
1238static int channel_match_by_glob(const char *channel_name, const void *pattern)
1239{
1240#if defined(HAVE_FNM_CASEFOLD)
1241 return fnmatch(pattern, channel_name, FNM_NOESCAPE | FNM_PATHNAME | FNM_CASEFOLD);
1242#else
1243 char *lower_channel_name = ast_str_to_lower(ast_strdup(channel_name));
1244 if (lower_channel_name) {
1245 int res = fnmatch(pattern, lower_channel_name, FNM_NOESCAPE | FNM_PATHNAME);
1246 ast_free(lower_channel_name);
1247 return res;
1248 }
1249 return FNM_NOMATCH;
1250#endif
1251}
1252
1254 struct ast_cli_args *a,
1255 int (*matchfn)(const char *, const void *),
1256 const void *data)
1257{
1258 struct ao2_container *cached_channels;
1259 struct ao2_iterator iter;
1260 struct ast_channel_snapshot *snapshot;
1261 struct ast_channel *c;
1262 int matched = 0;
1263
1264 cached_channels = ast_channel_cache_all();
1265
1266 iter = ao2_iterator_init(cached_channels, 0);
1267 for (; (snapshot = ao2_iterator_next(&iter)); ao2_ref(snapshot, -1)) {
1268 if ((!matchfn || !matchfn(snapshot->base->name, data))
1270 ast_cli(a->fd, "Requested Hangup on channel '%s'\n", snapshot->base->name);
1273 matched++;
1274 }
1275 }
1276 ao2_iterator_destroy(&iter);
1277 ao2_ref(cached_channels, -1);
1278
1279 return matched;
1280}
1281
1282#define arg_looks_like_regex(n) \
1283 (*n == '/' && n[strlen(n) - 1] == '/')
1284
1285#define arg_looks_like_glob(n) \
1286 (strcspn(n, "?*[") < strlen(n))
1287
1288static char *handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1289{
1290 struct ast_channel *c = NULL;
1291 static const char * const completions[] = { "all", NULL };
1292 char *complete = NULL;
1293 int x;
1294
1295 switch (cmd) {
1296 case CLI_INIT:
1297 e->command = "channel request hangup";
1298 e->usage =
1299 "Usage: channel request hangup <all>|<channel> [<channel> ...]\n"
1300 " Request that one or more channels be hung up. The hangup takes\n"
1301 " effect the next time the driver reads or writes from the channel.\n\n"
1302 " If 'all' is specified instead of a channel name, all channels\n"
1303 " will see the hangup request.\n\n"
1304 " A POSIX Extended Regular Expression can be provided in the place\n"
1305 " of a fixed channel name by wrapping it in forward slashes\n"
1306 " (e.g. /^PJSIP.*/). Note that the expression will match any part\n"
1307 " of the channel name unless anchored explicitly by ^ and/or $.\n\n"
1308 " Finally, wildcards (*) and other glob-like characters can also\n"
1309 " be used to match more than one channel. Similar to how path globs\n"
1310 " behave, a forward slash cannot be matched with a wildcard or\n"
1311 " bracket expression. In other words, if you want to hangup all\n"
1312 " Local channels, you must specify Local/* and not Loc*.\n";
1313 return NULL;
1314 case CLI_GENERATE:
1315 if (a->pos < e->args) {
1316 return NULL;
1317 } else if (a->pos == e->args) {
1318 complete = ast_cli_complete(a->word, completions, a->n);
1319 }
1320 if (!complete) {
1321 complete = ast_complete_channels(a->line, a->word, a->pos, a->n - 1, a->pos);
1322 }
1323 return complete;
1324 }
1325
1326 if (a->argc < 4) {
1327 return CLI_SHOWUSAGE;
1328 }
1329
1330 if (!strcasecmp(a->argv[3], "all")) {
1332 return CLI_SUCCESS;
1333 }
1334
1335 for (x = e->args; x < a->argc; x++) {
1336 /* Try to find a literal channel name first */
1337 if ((c = ast_channel_get_by_name(a->argv[x]))) {
1339 ast_cli(a->fd, "Requested Hangup on channel '%s'\n", ast_channel_name(c));
1343 continue;
1344 }
1345
1346 if (arg_looks_like_regex(a->argv[x])) {
1347 char *pattern = ast_strdup(a->argv[x]);
1348 regex_t re;
1349 int res;
1350
1351 if (!pattern) {
1352 return CLI_FAILURE;
1353 }
1354
1355 pattern[strlen(pattern) - 1] = 0;
1356 res = regcomp(&re, &pattern[1], REG_EXTENDED | REG_ICASE | REG_NOSUB);
1357 ast_free(pattern);
1358 if (res) {
1359 char errbuf[MAX_REGEX_ERROR_LEN];
1360 regerror(res, &re, errbuf, sizeof(errbuf));
1361 ast_cli(a->fd, "%s is not a valid POSIX Extended Regular Expression: %s\n",
1362 a->argv[x], errbuf);
1363 continue;
1364 }
1365
1367 ast_cli(a->fd, "%s did not match a known channel\n", a->argv[x]);
1368 }
1369 regfree(&re);
1370 } else if (arg_looks_like_glob(a->argv[x])) {
1371#if defined(HAVE_FNM_CASEFOLD)
1373 ast_cli(a->fd, "%s did not match a known channel\n", a->argv[x]);
1374 }
1375#else
1376 char *pattern = ast_str_to_lower(ast_strdup(a->argv[x]));
1377 if (pattern) {
1379 ast_cli(a->fd, "%s did not match a known channel\n", a->argv[x]);
1380 }
1381 ast_free(pattern);
1382 } else {
1383 return CLI_FAILURE;
1384 }
1385#endif
1386 } else {
1387 ast_cli(a->fd, "%s is not a known channel\n", a->argv[x]);
1388 }
1389 }
1390
1391 return CLI_SUCCESS;
1392}
1393
1394/*! \brief handles CLI command 'cli show permissions' */
1395static char *handle_cli_show_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1396{
1397 struct usergroup_cli_perm *cp;
1398 struct cli_perm *perm;
1399 struct passwd *pw = NULL;
1400 struct group *gr = NULL;
1401
1402 switch (cmd) {
1403 case CLI_INIT:
1404 e->command = "cli show permissions";
1405 e->usage =
1406 "Usage: cli show permissions\n"
1407 " Shows CLI configured permissions.\n";
1408 return NULL;
1409 case CLI_GENERATE:
1410 return NULL;
1411 }
1412
1414 AST_LIST_TRAVERSE(&cli_perms, cp, list) {
1415 if (cp->uid >= 0) {
1416 pw = getpwuid(cp->uid);
1417 if (pw) {
1418 ast_cli(a->fd, "user: %s [uid=%d]\n", pw->pw_name, cp->uid);
1419 }
1420 } else {
1421 gr = getgrgid(cp->gid);
1422 if (gr) {
1423 ast_cli(a->fd, "group: %s [gid=%d]\n", gr->gr_name, cp->gid);
1424 }
1425 }
1426 ast_cli(a->fd, "Permissions:\n");
1427 if (cp->perms) {
1428 AST_LIST_TRAVERSE(cp->perms, perm, list) {
1429 ast_cli(a->fd, "\t%s -> %s\n", perm->permit ? "permit" : "deny", perm->command);
1430 }
1431 }
1432 ast_cli(a->fd, "\n");
1433 }
1435
1436 return CLI_SUCCESS;
1437}
1438
1439/*! \brief handles CLI command 'cli reload permissions' */
1440static char *handle_cli_reload_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1441{
1442 switch (cmd) {
1443 case CLI_INIT:
1444 e->command = "cli reload permissions";
1445 e->usage =
1446 "Usage: cli reload permissions\n"
1447 " Reload the 'cli_permissions.conf' file.\n";
1448 return NULL;
1449 case CLI_GENERATE:
1450 return NULL;
1451 }
1452
1454
1455 return CLI_SUCCESS;
1456}
1457
1458/*! \brief handles CLI command 'cli check permissions' */
1459static char *handle_cli_check_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1460{
1461 struct passwd *pw = NULL;
1462 struct group *gr;
1463 int gid = -1, uid = -1;
1464 char command[AST_MAX_ARGS] = "";
1465 struct ast_cli_entry *ce = NULL;
1466 int found = 0;
1467 char *group, *tmp;
1468
1469 switch (cmd) {
1470 case CLI_INIT:
1471 e->command = "cli check permissions";
1472 e->usage =
1473 "Usage: cli check permissions {<username>|@<groupname>|<username>@<groupname>} [<command>]\n"
1474 " Check permissions config for a user@group or list the allowed commands for the specified user.\n"
1475 " The username or the groupname may be omitted.\n";
1476 return NULL;
1477 case CLI_GENERATE:
1478 if (a->pos >= 4) {
1479 return ast_cli_generator(a->line + strlen("cli check permissions") + strlen(a->argv[3]) + 1, a->word, a->n);
1480 }
1481 return NULL;
1482 }
1483
1484 if (a->argc < 4) {
1485 return CLI_SHOWUSAGE;
1486 }
1487
1488 tmp = ast_strdupa(a->argv[3]);
1489 group = strchr(tmp, '@');
1490 if (group) {
1491 gr = getgrnam(&group[1]);
1492 if (!gr) {
1493 ast_cli(a->fd, "Unknown group '%s'\n", &group[1]);
1494 return CLI_FAILURE;
1495 }
1496 group[0] = '\0';
1497 gid = gr->gr_gid;
1498 }
1499
1500 if (!group && ast_strlen_zero(tmp)) {
1501 ast_cli(a->fd, "You didn't supply a username\n");
1502 } else if (!ast_strlen_zero(tmp) && !(pw = getpwnam(tmp))) {
1503 ast_cli(a->fd, "Unknown user '%s'\n", tmp);
1504 return CLI_FAILURE;
1505 } else if (pw) {
1506 uid = pw->pw_uid;
1507 }
1508
1509 if (a->argc == 4) {
1510 while ((ce = cli_next(ce))) {
1511 /* Hide commands that start with '_' */
1512 if (ce->_full_cmd[0] == '_') {
1513 continue;
1514 }
1515 if (cli_has_permissions(uid, gid, ce->_full_cmd)) {
1516 ast_cli(a->fd, "%30.30s %s\n", ce->_full_cmd, S_OR(ce->summary, "<no description available>"));
1517 found++;
1518 }
1519 }
1520 if (!found) {
1521 ast_cli(a->fd, "You are not allowed to run any command on Asterisk\n");
1522 }
1523 } else {
1524 ast_join(command, sizeof(command), a->argv + 4);
1525 ast_cli(a->fd, "%s '%s%s%s' is %s to run command: '%s'\n", uid >= 0 ? "User" : "Group", tmp,
1526 group && uid >= 0 ? "@" : "",
1527 group ? &group[1] : "",
1528 cli_has_permissions(uid, gid, command) ? "allowed" : "not allowed", command);
1529 }
1530
1531 return CLI_SUCCESS;
1532}
1533
1534static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
1535
1536static char *handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1537{
1538 char *buf, *obuf;
1539 int buflen = 2048;
1540 int len = 0;
1541 char **matches;
1542 int x, matchlen;
1543
1544 switch (cmd) {
1545 case CLI_INIT:
1546 e->command = "_command matchesarray";
1547 e->usage =
1548 "Usage: _command matchesarray \"<line>\" text \n"
1549 " This function is used internally to help with command completion and should.\n"
1550 " never be called by the user directly.\n";
1551 return NULL;
1552 case CLI_GENERATE:
1553 return NULL;
1554 }
1555
1556 if (a->argc != 4)
1557 return CLI_SHOWUSAGE;
1558 if (!(buf = ast_malloc(buflen)))
1559 return CLI_FAILURE;
1560 buf[len] = '\0';
1561 matches = ast_cli_completion_matches(a->argv[2], a->argv[3]);
1562 if (matches) {
1563 for (x=0; matches[x]; x++) {
1564 matchlen = strlen(matches[x]) + 1;
1565 if (len + matchlen >= buflen) {
1566 buflen += matchlen * 3;
1567 obuf = buf;
1568 if (!(buf = ast_realloc(obuf, buflen)))
1569 /* Memory allocation failure... Just free old buffer and be done */
1570 ast_free(obuf);
1571 }
1572 if (buf)
1573 len += sprintf( buf + len, "%s ", matches[x]);
1574 ast_free(matches[x]);
1575 matches[x] = NULL;
1576 }
1577 ast_free(matches);
1578 }
1579
1580 if (buf) {
1581 ast_cli(a->fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
1582 ast_free(buf);
1583 } else
1584 ast_cli(a->fd, "NULL\n");
1585
1586 return CLI_SUCCESS;
1587}
1588
1589
1594
1595static int channel_set_debug(void *obj, void *arg, void *data, int flags)
1596{
1597 struct ast_channel *chan = obj;
1598 struct channel_set_debug_args *args = data;
1599
1600 ast_channel_lock(chan);
1601
1602 if (!(ast_channel_fin(chan) & DEBUGCHAN_FLAG) || !(ast_channel_fout(chan) & DEBUGCHAN_FLAG)) {
1603 if (args->is_off) {
1606 } else {
1609 }
1610 ast_cli(args->fd, "Debugging %s on channel %s\n", args->is_off ? "disabled" : "enabled",
1611 ast_channel_name(chan));
1612 }
1613
1614 ast_channel_unlock(chan);
1615
1616 return 0;
1617}
1618
1619static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1620{
1621 struct ast_channel *c = NULL;
1622 static const char * const completions_all[] = { "all", NULL };
1623 static const char * const completions_off[] = { "off", NULL };
1624 struct channel_set_debug_args args = {
1625 .fd = a->fd,
1626 };
1627
1628 switch (cmd) {
1629 case CLI_INIT:
1630 e->command = "core set debug channel";
1631 e->usage =
1632 "Usage: core set debug channel <all|channel> [off]\n"
1633 " Enables/disables debugging on all or on a specific channel.\n";
1634 return NULL;
1635 case CLI_GENERATE:
1636 if (a->pos == 4) {
1637 char *complete = ast_cli_complete(a->word, completions_all, a->n);
1638 if (!complete) {
1639 complete = ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args);
1640 }
1641 return complete;
1642 } else if (a->pos == 5) {
1643 return ast_cli_complete(a->word, completions_off, a->n);
1644 }
1645
1646 return NULL;
1647 }
1648
1649 if (a->argc == e->args + 2) {
1650 /* 'core set debug channel {all|chan_id}' */
1651 if (!strcasecmp(a->argv[e->args + 1], "off"))
1652 args.is_off = 1;
1653 else
1654 return CLI_SHOWUSAGE;
1655 } else if (a->argc != e->args + 1) {
1656 return CLI_SHOWUSAGE;
1657 }
1658
1659 if (!strcasecmp("all", a->argv[e->args])) {
1660 if (args.is_off) {
1661 global_fin &= ~DEBUGCHAN_FLAG;
1662 global_fout &= ~DEBUGCHAN_FLAG;
1663 } else {
1666 }
1668 } else {
1669 if ((c = ast_channel_get_by_name(a->argv[e->args]))) {
1672 } else {
1673 ast_cli(a->fd, "No such channel %s\n", a->argv[e->args]);
1674 }
1675 }
1676
1677 ast_cli(a->fd, "Debugging on new channels is %s\n", args.is_off ? "disabled" : "enabled");
1678
1679 return CLI_SUCCESS;
1680}
1681
1682static char *handle_debug_category(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1683{
1684 const char *argv4 = a->argv ? S_OR(a->argv[4], "") : "";
1685 int offset = strncasecmp(argv4, "off", strlen(argv4)) ? 0 : 1;
1686
1687 switch (cmd) {
1688 case CLI_INIT:
1689 e->command = "core set debug category";
1690 e->usage =
1691 "Usage: core set debug category <category>[:<sublevel>] [category[:<sublevel] ...]\n"
1692 " core set debug category off [<category> [<category>] ...]\n\n"
1693 " Allows enabling and disabling debug logging categories.\n"
1694 " When a category is enabled all relevant debug messages are logged\n"
1695 " for a given category. However, if a sublevel is specified only\n"
1696 " those categorized messages at or below the coded debug sublevel\n"
1697 " are logged.\n";
1698 return NULL;
1699
1700 case CLI_GENERATE:
1701 if (a->pos < e->args) {
1702 return NULL;
1703 }
1704
1705 if (a->pos == 4 && offset) {
1707 }
1708
1709 return ast_debug_category_complete(a->argv + 4,
1710 a->pos - e->args, a->word, a->n - 1);
1711 }
1712
1713 if (a->argc <= e->args) {
1714 return CLI_SHOWUSAGE;
1715 }
1716
1717 ast_debug_category_set_sublevels(a->argv + e->args + offset, a->argc - e->args - offset,
1719
1720 return CLI_SUCCESS;
1721}
1722
1723static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1724{
1725 struct ast_channel *chan;
1726 struct timeval now;
1727 char cdrtime[256];
1728 struct ast_str *obuf;/*!< Buffer for CDR variables. */
1729 struct ast_str *output;/*!< Accumulation buffer for all output. */
1730 long elapsed_seconds=0;
1731 int hour=0, min=0, sec=0;
1732 struct ast_var_t *var;
1733 struct ast_str *write_transpath = ast_str_alloca(256);
1734 struct ast_str *read_transpath = ast_str_alloca(256);
1735 struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1736 struct ast_bridge *bridge;
1738 char callid_buf[32];
1739 int stream_num;
1740 RAII_VAR(char *, tenant_id, NULL, ast_free);
1741
1742 switch (cmd) {
1743 case CLI_INIT:
1744 e->command = "core show channel";
1745 e->usage =
1746 "Usage: core show channel <channel>\n"
1747 " Shows lots of information about the specified channel.\n";
1748 return NULL;
1749 case CLI_GENERATE:
1750 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1751 }
1752
1753 if (a->argc != 4) {
1754 return CLI_SHOWUSAGE;
1755 }
1756
1757 obuf = ast_str_thread_get(&ast_str_thread_global_buf, 16);
1758 if (!obuf) {
1759 return CLI_FAILURE;
1760 }
1761
1762 chan = ast_channel_get_by_name(a->argv[3]);
1763 if (!chan) {
1764 ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
1765
1766 return CLI_SUCCESS;
1767 }
1768
1769 output = ast_str_create(8192);
1770 if (!output) {
1771 ast_channel_unref(chan);
1772
1773 return CLI_FAILURE;
1774 }
1775
1776 now = ast_tvnow();
1777 ast_channel_lock(chan);
1778
1780 elapsed_seconds = now.tv_sec - ast_channel_creationtime(chan).tv_sec;
1781 hour = elapsed_seconds / 3600;
1782 min = (elapsed_seconds % 3600) / 60;
1783 sec = elapsed_seconds % 60;
1784 snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
1785 } else {
1786 strcpy(cdrtime, "N/A");
1787 }
1788
1789 ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath);
1790 ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath);
1791
1792 bridge = ast_channel_get_bridge(chan);
1793 callid_buf[0] = '\0';
1794 callid = ast_channel_callid(chan);
1795 if (callid) {
1796 ast_callid_strnprint(callid_buf, sizeof(callid_buf), callid);
1797 }
1798
1800 ast_asprintf(&tenant_id, " TenantID: %s\n", ast_channel_tenantid(chan));
1801 }
1802
1803 ast_str_append(&output, 0,
1804 " -- General --\n"
1805 " Name: %s\n"
1806 " Type: %s\n"
1807 " UniqueID: %s\n"
1808 " LinkedID: %s\n"
1809 "%s"
1810 " Caller ID: %s\n"
1811 " Caller ID Name: %s\n"
1812 "Connected Line ID: %s\n"
1813 "Connected Line ID Name: %s\n"
1814 "Eff. Connected Line ID: %s\n"
1815 "Eff. Connected Line ID Name: %s\n"
1816 " DNID Digits: %s\n"
1817 " Language: %s\n"
1818 " State: %s (%u)\n"
1819 " NativeFormats: %s\n"
1820 " WriteFormat: %s\n"
1821 " ReadFormat: %s\n"
1822 " WriteTranscode: %s %s\n"
1823 " ReadTranscode: %s %s\n"
1824 " Time to Hangup: %ld\n"
1825 " Elapsed Time: %s\n"
1826 " Bridge ID: %s\n"
1827 " -- PBX --\n"
1828 " Context: %s\n"
1829 " Extension: %s\n"
1830 " Priority: %d\n"
1831 " Call Group: %llu\n"
1832 " Pickup Group: %llu\n"
1833 " Application: %s\n"
1834 " Data: %s\n"
1835 " Call Identifier: %s\n",
1836 ast_channel_name(chan),
1837 ast_channel_tech(chan)->type,
1840 !ast_strlen_zero(tenant_id) ? tenant_id : "",
1841 S_COR(ast_channel_caller(chan)->id.number.valid,
1842 ast_channel_caller(chan)->id.number.str, "(N/A)"),
1843 S_COR(ast_channel_caller(chan)->id.name.valid,
1844 ast_channel_caller(chan)->id.name.str, "(N/A)"),
1845 S_COR(ast_channel_connected(chan)->id.number.valid,
1846 ast_channel_connected(chan)->id.number.str, "(N/A)"),
1847 S_COR(ast_channel_connected(chan)->id.name.valid,
1848 ast_channel_connected(chan)->id.name.str, "(N/A)"),
1850 ast_channel_connected_effective_id(chan).number.str, "(N/A)"),
1852 ast_channel_connected_effective_id(chan).name.str, "(N/A)"),
1853 S_OR(ast_channel_dialed(chan)->number.str, "(N/A)"),
1856 ast_channel_state(chan),
1860 ast_str_strlen(write_transpath) ? "Yes" : "No",
1861 ast_str_buffer(write_transpath),
1862 ast_str_strlen(read_transpath) ? "Yes" : "No",
1863 ast_str_buffer(read_transpath),
1864 (long)ast_channel_whentohangup(chan)->tv_sec,
1865 cdrtime,
1866 bridge ? bridge->uniqueid : "(Not bridged)",
1867 ast_channel_context(chan),
1868 ast_channel_exten(chan),
1872 S_OR(ast_channel_appl(chan), "(N/A)"),
1873 S_OR(ast_channel_data(chan), "(Empty)"),
1874 S_OR(callid_buf, "(None)")
1875 );
1876
1877 ast_str_append(&output, 0, " Variables:\n");
1878
1879 AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
1880 ast_str_append(&output, 0, "%s=%s\n", ast_var_name(var), ast_var_value(var));
1881 }
1882
1883 if (!(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)
1884 && ast_cdr_serialize_variables(ast_channel_name(chan), &obuf, '=', '\n')) {
1885 ast_str_append(&output, 0, " CDR Variables:\n%s\n", ast_str_buffer(obuf));
1886 }
1887
1888 ast_str_append(&output, 0, " -- Streams --\n");
1889 for (stream_num = 0; stream_num < ast_stream_topology_get_count(ast_channel_get_stream_topology(chan)); stream_num++) {
1891 struct ast_variable *metadata = ast_stream_get_metadata_list(stream);
1892
1893 ast_str_append(&output, 0,
1894 "Name: %s\n"
1895 " Type: %s\n"
1896 " State: %s\n"
1897 " Group: %d\n"
1898 " Formats: %s\n"
1899 " Metadata:\n",
1900 ast_stream_get_name(stream),
1903 ast_stream_get_group(stream),
1905 );
1906
1907 if (metadata) {
1908 struct ast_variable *v;
1909 for(v = metadata; v; v = v->next) {
1910 ast_str_append(&output, 0, " %s: %s\n", v->name, v->value);
1911 }
1912 ast_variables_destroy(metadata);
1913 }
1914 }
1915
1916 ast_channel_unlock(chan);
1917
1918 ast_cli(a->fd, "%s", ast_str_buffer(output));
1919 ast_free(output);
1920
1921 ao2_cleanup(bridge);
1922 ast_channel_unref(chan);
1923
1924 return CLI_SUCCESS;
1925}
1926
1927/*
1928 * helper function to generate CLI matches from a fixed set of values.
1929 * A NULL word is acceptable.
1930 */
1931char *ast_cli_complete(const char *word, const char * const choices[], int state)
1932{
1933 int i, which = 0, len;
1934 len = ast_strlen_zero(word) ? 0 : strlen(word);
1935
1936 for (i = 0; choices[i]; i++) {
1937 if ((!len || !strncasecmp(word, choices[i], len)) && ++which > state) {
1938 if (state != -1) {
1939 return ast_strdup(choices[i]);
1940 }
1941
1942 if (ast_cli_completion_add(ast_strdup(choices[i]))) {
1943 return NULL;
1944 }
1945 }
1946 }
1947 return NULL;
1948}
1949
1950char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
1951{
1952 int wordlen = strlen(word), which = 0;
1953 struct ao2_container *cached_channels;
1954 char *ret = NULL;
1955 struct ao2_iterator iter;
1956 struct ast_channel_snapshot *snapshot;
1957
1958 if (pos != rpos) {
1959 return NULL;
1960 }
1961
1962 cached_channels = ast_channel_cache_all();
1963
1964 iter = ao2_iterator_init(cached_channels, 0);
1965 for (; (snapshot = ao2_iterator_next(&iter)); ao2_ref(snapshot, -1)) {
1966 if (!strncasecmp(word, snapshot->base->name, wordlen) && (++which > state)) {
1967 if (state != -1) {
1968 ret = ast_strdup(snapshot->base->name);
1969 ao2_ref(snapshot, -1);
1970 break;
1971 }
1972
1973 if (ast_cli_completion_add(ast_strdup(snapshot->base->name))) {
1974 ao2_ref(snapshot, -1);
1975 break;
1976 }
1977 }
1978 }
1979 ao2_iterator_destroy(&iter);
1980 ao2_ref(cached_channels, -1);
1981
1982 return ret;
1983}
1984
1985static char *group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1986{
1987#define FORMAT_STRING "%-25s %-20s %-20s\n"
1988
1989 struct ast_group_info *gi = NULL;
1990 int numchans = 0;
1991 regex_t regexbuf;
1992 int havepattern = 0;
1993
1994 switch (cmd) {
1995 case CLI_INIT:
1996 e->command = "group show channels";
1997 e->usage =
1998 "Usage: group show channels [pattern]\n"
1999 " Lists all currently active channels with channel group(s) specified.\n"
2000 " Optional regular expression pattern is matched to group names for each\n"
2001 " channel.\n";
2002 return NULL;
2003 case CLI_GENERATE:
2004 return NULL;
2005 }
2006
2007 if (a->argc < 3 || a->argc > 4)
2008 return CLI_SHOWUSAGE;
2009
2010 if (a->argc == 4) {
2011 if (regcomp(&regexbuf, a->argv[3], REG_EXTENDED | REG_NOSUB))
2012 return CLI_SHOWUSAGE;
2013 havepattern = 1;
2014 }
2015
2016 ast_cli(a->fd, FORMAT_STRING, "Channel", "Group", "Category");
2017
2019
2021 while (gi) {
2022 if (!havepattern || !regexec(&regexbuf, gi->group, 0, NULL, 0)) {
2023 ast_cli(a->fd, FORMAT_STRING, ast_channel_name(gi->chan), gi->group, (ast_strlen_zero(gi->category) ? "(default)" : gi->category));
2024 numchans++;
2025 }
2026 gi = AST_LIST_NEXT(gi, group_list);
2027 }
2028
2030
2031 if (havepattern)
2032 regfree(&regexbuf);
2033
2034 ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
2035 return CLI_SUCCESS;
2036#undef FORMAT_STRING
2037}
2038
2039static char *handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2040{
2041 switch (cmd) {
2042 case CLI_INIT:
2043 e->command = "core waitfullybooted";
2044 e->usage =
2045 "Usage: core waitfullybooted\n"
2046 " Wait until Asterisk has fully booted.\n";
2047 return NULL;
2048 case CLI_GENERATE:
2049 return NULL;
2050 }
2051
2052 while (!ast_fully_booted) {
2053 usleep(100);
2054 }
2055
2056 ast_cli(a->fd, "Asterisk has fully booted.\n");
2057
2058 return CLI_SUCCESS;
2059}
2060
2061
2062#ifdef HAVE_MALLOC_TRIM
2063
2064/*!
2065 * \internal
2066 * \brief Attempt to reclaim unused heap memory.
2067 *
2068 * Users have reported that asterisk will sometimes be killed because it can't allocate
2069 * more than around 3G of memory on a 32 bit system.
2070 *
2071 * Using malloc_trim() will help us to determine if it's because there's a leak or because
2072 * the heap is so fragmented that there isn't enough contiguous memory available.
2073 *
2074 * \note malloc_trim() is a GNU extension and is therefore not portable.
2075 */
2076static char *handle_cli_malloc_trim(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2077{
2078 extern int malloc_trim(size_t __pad) __THROW;
2079
2080 switch (cmd) {
2081 case CLI_INIT:
2082 e->command = "malloc trim";
2083 e->usage =
2084 "Usage: malloc trim\n"
2085 " Try to give excess memory back to the OS.\n";
2086 return NULL;
2087 case CLI_GENERATE:
2088 return NULL;
2089 }
2090
2091 if (malloc_trim(0)) {
2092 ast_cli(a->fd, "Returned some memory to the OS.\n");
2093 } else {
2094 ast_cli(a->fd, "No memory returned to the OS.\n");
2095 }
2096
2097 return CLI_SUCCESS;
2098}
2099
2100#endif
2101
2102static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
2103
2104static struct ast_cli_entry cli_cli[] = {
2105 AST_CLI_DEFINE(handle_commandmatchesarray, "Returns command matches array"),
2106
2107 AST_CLI_DEFINE(handle_debug_category, "Enable/disable debugging categories"),
2108
2109 AST_CLI_DEFINE(handle_debug, "Set level of debug chattiness"),
2110 AST_CLI_DEFINE(handle_trace, "Set level of trace chattiness"),
2111 AST_CLI_DEFINE(handle_verbose, "Set level of verbose chattiness"),
2112
2113 AST_CLI_DEFINE(handle_help, "Display help list, or specific help on a command"),
2114 AST_CLI_DEFINE(handle_logger_mute, "Toggle logging output to a console"),
2115
2116 AST_CLI_DEFINE(handle_modlist, "List modules and info"),
2117 AST_CLI_DEFINE(handle_load, "Load a module by name"),
2118 AST_CLI_DEFINE(handle_reload, "Reload configuration for a module"),
2119 AST_CLI_DEFINE(handle_core_reload, "Global reload"),
2120 AST_CLI_DEFINE(handle_unload, "Unload a module by name"),
2121 AST_CLI_DEFINE(handle_refresh, "Completely unloads and loads a module by name"),
2122
2123 AST_CLI_DEFINE(handle_showuptime, "Show uptime information"),
2124
2125 AST_CLI_DEFINE(handle_cli_reload_permissions, "Reload CLI permissions config"),
2126 AST_CLI_DEFINE(handle_cli_show_permissions, "Show CLI permissions"),
2127 AST_CLI_DEFINE(handle_cli_check_permissions, "Try a permissions config for a user"),
2128 AST_CLI_DEFINE(handle_cli_wait_fullybooted, "Wait for Asterisk to be fully booted"),
2129
2130#ifdef HAVE_MALLOC_TRIM
2131 AST_CLI_DEFINE(handle_cli_malloc_trim, "Return excess memory to the OS"),
2132#endif
2133
2134};
2135
2137 AST_CLI_DEFINE(handle_chanlist, "Display information on channels"),
2138 AST_CLI_DEFINE(handle_showcalls, "Display information on calls"),
2139 AST_CLI_DEFINE(handle_showchan, "Display information on a specific channel"),
2140 AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
2141 AST_CLI_DEFINE(group_show_channels, "Display active channels with group(s)"),
2142 AST_CLI_DEFINE(handle_softhangup, "Request a hangup on a given channel"),
2143};
2144
2145/*!
2146 * Some regexp characters in cli arguments are reserved and used as separators.
2147 */
2148static const char cli_rsvd[] = "[]{}|*%";
2149
2150/*!
2151 * initialize the _full_cmd string and related parameters,
2152 * return 0 on success, -1 on error.
2153 */
2154static int set_full_cmd(struct ast_cli_entry *e)
2155{
2156 int i;
2157 char buf[80];
2158
2159 ast_join(buf, sizeof(buf), e->cmda);
2160 e->_full_cmd = ast_strdup(buf);
2161 if (!e->_full_cmd) {
2162 ast_log(LOG_WARNING, "-- cannot allocate <%s>\n", buf);
2163 return -1;
2164 }
2165 e->cmdlen = strcspn(e->_full_cmd, cli_rsvd);
2166 for (i = 0; e->cmda[i]; i++)
2167 ;
2168 e->args = i;
2169 return 0;
2170}
2171
2172/*! \brief cleanup (free) cli_perms linkedlist. */
2173static void destroy_user_perms(void)
2174{
2175 struct cli_perm *perm;
2176 struct usergroup_cli_perm *user_perm;
2177
2179 while ((user_perm = AST_LIST_REMOVE_HEAD(&cli_perms, list))) {
2180 while ((perm = AST_LIST_REMOVE_HEAD(user_perm->perms, list))) {
2181 ast_free(perm->command);
2182 ast_free(perm);
2183 }
2184 ast_free(user_perm);
2185 }
2187}
2188
2190{
2191 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
2192 struct ast_config *cfg;
2193 char *cat = NULL;
2194 struct ast_variable *v;
2195 struct usergroup_cli_perm *user_group, *cp_entry;
2196 struct cli_perm *perm = NULL;
2197 struct passwd *pw;
2198 struct group *gr;
2199
2201 ast_log(LOG_NOTICE, "You must wait until last 'cli reload permissions' command finish\n");
2202 return 1;
2203 }
2204
2205 cfg = ast_config_load2(perms_config, "" /* core, can't reload */, config_flags);
2206 if (!cfg) {
2208 return 1;
2209 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
2211 return 0;
2212 }
2213
2214 /* free current structures. */
2216
2217 while ((cat = ast_category_browse(cfg, cat))) {
2218 if (!strcasecmp(cat, "general")) {
2219 /* General options */
2220 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
2221 if (!strcasecmp(v->name, "default_perm")) {
2222 cli_default_perm = (!strcasecmp(v->value, "permit")) ? 1: 0;
2223 }
2224 }
2225 continue;
2226 }
2227
2228 /* users or groups */
2229 gr = NULL, pw = NULL;
2230 if (cat[0] == '@') {
2231 /* This is a group */
2232 gr = getgrnam(&cat[1]);
2233 if (!gr) {
2234 ast_log (LOG_WARNING, "Unknown group '%s'\n", &cat[1]);
2235 continue;
2236 }
2237 } else {
2238 /* This is a user */
2239 pw = getpwnam(cat);
2240 if (!pw) {
2241 ast_log (LOG_WARNING, "Unknown user '%s'\n", cat);
2242 continue;
2243 }
2244 }
2245 user_group = NULL;
2246 /* Check for duplicates */
2248 AST_LIST_TRAVERSE(&cli_perms, cp_entry, list) {
2249 if ((pw && cp_entry->uid == pw->pw_uid) || (gr && cp_entry->gid == gr->gr_gid)) {
2250 /* if it is duplicated, just added this new settings, to
2251 the current list. */
2252 user_group = cp_entry;
2253 break;
2254 }
2255 }
2257
2258 if (!user_group) {
2259 /* alloc space for the new user config. */
2260 user_group = ast_calloc(1, sizeof(*user_group));
2261 if (!user_group) {
2262 continue;
2263 }
2264 user_group->uid = (pw ? pw->pw_uid : -1);
2265 user_group->gid = (gr ? gr->gr_gid : -1);
2266 user_group->perms = ast_calloc(1, sizeof(*user_group->perms));
2267 if (!user_group->perms) {
2268 ast_free(user_group);
2269 continue;
2270 }
2271 }
2272 for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
2273 if (ast_strlen_zero(v->value)) {
2274 /* we need to check this condition cause it could break security. */
2275 ast_log(LOG_WARNING, "Empty permit/deny option in user '%s'\n", cat);
2276 continue;
2277 }
2278 if (!strcasecmp(v->name, "permit")) {
2279 perm = ast_calloc(1, sizeof(*perm));
2280 if (perm) {
2281 perm->permit = 1;
2282 perm->command = ast_strdup(v->value);
2283 }
2284 } else if (!strcasecmp(v->name, "deny")) {
2285 perm = ast_calloc(1, sizeof(*perm));
2286 if (perm) {
2287 perm->permit = 0;
2288 perm->command = ast_strdup(v->value);
2289 }
2290 } else {
2291 /* up to now, only 'permit' and 'deny' are possible values. */
2292 ast_log(LOG_WARNING, "Unknown '%s' option\n", v->name);
2293 continue;
2294 }
2295 if (perm) {
2296 /* Added the permission to the user's list. */
2297 AST_LIST_INSERT_TAIL(user_group->perms, perm, list);
2298 perm = NULL;
2299 }
2300 }
2302 AST_RWLIST_INSERT_TAIL(&cli_perms, user_group, list);
2304 }
2305
2306 ast_config_destroy(cfg);
2308 return 0;
2309}
2310
2315
2320
2321/*! \brief initialize the _full_cmd string in * each of the builtins. */
2328
2334
2335/*!
2336 * match a word in the CLI entry.
2337 * returns -1 on mismatch, 0 on match of an optional word,
2338 * 1 on match of a full word.
2339 *
2340 * The pattern can be
2341 * any_word match for equal
2342 * [foo|bar|baz] optionally, one of these words
2343 * {foo|bar|baz} exactly, one of these words
2344 * % any word
2345 */
2346static int word_match(const char *cmd, const char *cli_word)
2347{
2348 int l;
2349 char *pos;
2350
2351 if (ast_strlen_zero(cmd) || ast_strlen_zero(cli_word))
2352 return -1;
2353 if (!strchr(cli_rsvd, cli_word[0])) /* normal match */
2354 return (strcasecmp(cmd, cli_word) == 0) ? 1 : -1;
2355 l = strlen(cmd);
2356 /* wildcard match - will extend in the future */
2357 if (l > 0 && cli_word[0] == '%') {
2358 return 1; /* wildcard */
2359 }
2360
2361 /* Start a search for the command entered against the cli word in question */
2362 pos = strcasestr(cli_word, cmd);
2363 while (pos) {
2364
2365 /*
2366 *Check if the word matched with is surrounded by reserved characters on both sides
2367 * and isn't at the beginning of the cli_word since that would make it check in a location we shouldn't know about.
2368 * If it is surrounded by reserved chars and isn't at the beginning, it's a match.
2369 */
2370 if (pos != cli_word && strchr(cli_rsvd, pos[-1]) && strchr(cli_rsvd, pos[l])) {
2371 return 1; /* valid match */
2372 }
2373
2374 /* Ok, that one didn't match, strcasestr to the next appearance of the command and start over.*/
2375 pos = strcasestr(pos + 1, cmd);
2376 }
2377 /* If no matches were found over the course of the while loop, we hit the end of the string. It's a mismatch. */
2378 return -1;
2379}
2380
2381/*! \brief if word is a valid prefix for token, returns the pos-th
2382 * match as a malloced string, or NULL otherwise.
2383 * Always tell in *actual how many matches we got.
2384 */
2385static char *is_prefix(const char *word, const char *token,
2386 int pos, int *actual)
2387{
2388 int lw;
2389 char *s, *t1;
2390
2391 *actual = 0;
2392 if (ast_strlen_zero(token))
2393 return NULL;
2394 if (ast_strlen_zero(word))
2395 word = ""; /* dummy */
2396 lw = strlen(word);
2397 if (strcspn(word, cli_rsvd) != lw)
2398 return NULL; /* no match if word has reserved chars */
2399 if (strchr(cli_rsvd, token[0]) == NULL) { /* regular match */
2400 if (strncasecmp(token, word, lw)) /* no match */
2401 return NULL;
2402 *actual = 1;
2403 return (pos != 0) ? NULL : ast_strdup(token);
2404 }
2405 /* now handle regexp match */
2406
2407 /* Wildcard always matches, so we never do is_prefix on them */
2408
2409 t1 = ast_strdupa(token + 1); /* copy, skipping first char */
2410 while (pos >= 0 && (s = strsep(&t1, cli_rsvd)) && *s) {
2411 if (*s == '%') /* wildcard */
2412 continue;
2413 if (strncasecmp(s, word, lw)) /* no match */
2414 continue;
2415 (*actual)++;
2416 if (pos-- == 0)
2417 return ast_strdup(s);
2418 }
2419 return NULL;
2420}
2421
2422/*!
2423 * \internal
2424 * \brief locate a cli command in the 'helpers' list (which must be locked).
2425 * The search compares word by word taking care of regexps in e->cmda
2426 * This function will return NULL when nothing is matched, or the ast_cli_entry that matched.
2427 * \param cmds
2428 * \param match_type has 3 possible values:
2429 * 0 returns if the search key is equal or longer than the entry.
2430 * note that trailing optional arguments are skipped.
2431 * -1 true if the mismatch is on the last word XXX not true!
2432 * 1 true only on complete, exact match.
2433 *
2434 */
2435static struct ast_cli_entry *find_cli(const char * const cmds[], int match_type)
2436{
2437 int matchlen = -1; /* length of longest match so far */
2438 struct ast_cli_entry *cand = NULL, *e=NULL;
2439
2440 while ( (e = cli_next(e)) ) {
2441 /* word-by word regexp comparison */
2442 const char * const *src = cmds;
2443 const char * const *dst = e->cmda;
2444 int n = 0;
2445 for (;; dst++, src += n) {
2446 n = word_match(*src, *dst);
2447 if (n < 0)
2448 break;
2449 }
2450 if (ast_strlen_zero(*dst) || ((*dst)[0] == '[' && ast_strlen_zero(dst[1]))) {
2451 /* no more words in 'e' */
2452 if (ast_strlen_zero(*src)) /* exact match, cannot do better */
2453 break;
2454 /* Here, cmds has more words than the entry 'e' */
2455 if (match_type != 0) /* but we look for almost exact match... */
2456 continue; /* so we skip this one. */
2457 /* otherwise we like it (case 0) */
2458 } else { /* still words in 'e' */
2459 if (ast_strlen_zero(*src))
2460 continue; /* cmds is shorter than 'e', not good */
2461 /* Here we have leftover words in cmds and 'e',
2462 * but there is a mismatch. We only accept this one if match_type == -1
2463 * and this is the last word for both.
2464 */
2465 if (match_type != -1 || !ast_strlen_zero(src[1]) ||
2466 !ast_strlen_zero(dst[1])) /* not the one we look for */
2467 continue;
2468 /* good, we are in case match_type == -1 and mismatch on last word */
2469 }
2470 if (src - cmds > matchlen) { /* remember the candidate */
2471 matchlen = src - cmds;
2472 cand = e;
2473 }
2474 }
2475
2476 return e ? e : cand;
2477}
2478
2479static char *find_best(const char *argv[])
2480{
2481 static char cmdline[80];
2482 int x;
2483 /* See how close we get, then print the candidate */
2484 const char *myargv[AST_MAX_CMD_LEN] = { NULL, };
2485
2487 for (x = 0; argv[x]; x++) {
2488 myargv[x] = argv[x];
2489 if (!find_cli(myargv, -1))
2490 break;
2491 }
2493 ast_join(cmdline, sizeof(cmdline), myargv);
2494 return cmdline;
2495}
2496
2498{
2499 struct ast_cli_entry *cur = NULL;
2500
2501 while ((cur = cli_next(cur))) {
2502 if (cur == e) {
2503 return 1;
2504 }
2505 }
2506 return 0;
2507}
2508
2515
2517{
2518 if (e->inuse) {
2519 ast_log(LOG_WARNING, "Can't remove command that is in use\n");
2520 } else {
2525 ast_free(e->_full_cmd);
2526 e->_full_cmd = NULL;
2527 if (e->handler) {
2528 /* this is a new-style entry. Reset fields and free memory. */
2529 char *cmda = (char *) e->cmda;
2530 memset(cmda, '\0', sizeof(e->cmda));
2531 ast_free(e->command);
2532 e->command = NULL;
2533 e->usage = NULL;
2534 }
2535 }
2536 return 0;
2537}
2538
2539int __ast_cli_register(struct ast_cli_entry *e, struct ast_module *module)
2540{
2541 struct ast_cli_entry *cur;
2542 int i, lf, ret = -1;
2543
2544 struct ast_cli_args a; /* fake argument */
2545 char **dst = (char **)e->cmda; /* need to cast as the entry is readonly */
2546 char *s;
2547
2549
2550 if (cli_is_registered(e)) {
2551 ast_log(LOG_WARNING, "Command '%s' already registered (the same ast_cli_entry)\n",
2552 S_OR(e->_full_cmd, e->command));
2553 ret = 0; /* report success */
2554 goto done;
2555 }
2556
2557 memset(&a, '\0', sizeof(a));
2558
2559 e->module = module;
2560 /* No module reference needed here, the module called us. */
2561 e->handler(e, CLI_INIT, &a);
2562
2563 /* XXX check that usage and command are filled up */
2564 s = ast_skip_blanks(e->command);
2565 s = e->command = ast_strdup(s);
2566 for (i=0; !ast_strlen_zero(s) && i < AST_MAX_CMD_LEN-1; i++) {
2567 *dst++ = s; /* store string */
2568 s = ast_skip_nonblanks(s);
2569 if (*s == '\0') /* we are done */
2570 break;
2571 *s++ = '\0';
2572 s = ast_skip_blanks(s);
2573 }
2574 *dst++ = NULL;
2575
2576 if (find_cli(e->cmda, 1)) {
2577 ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n",
2578 S_OR(e->_full_cmd, e->command));
2579 goto done;
2580 }
2581 if (set_full_cmd(e)) {
2582 ast_log(LOG_WARNING, "Error registering CLI Command '%s'\n",
2583 S_OR(e->_full_cmd, e->command));
2584 goto done;
2585 }
2586
2587 lf = e->cmdlen;
2589 int len = cur->cmdlen;
2590 if (lf < len)
2591 len = lf;
2592 if (strncasecmp(e->_full_cmd, cur->_full_cmd, len) < 0) {
2594 break;
2595 }
2596 }
2598
2599 if (!cur)
2601 ret = 0; /* success */
2602
2603done:
2605 if (ret) {
2606 ast_free(e->command);
2607 e->command = NULL;
2608 }
2609
2610 return ret;
2611}
2612
2613/*
2614 * register/unregister an array of entries.
2615 */
2616int __ast_cli_register_multiple(struct ast_cli_entry *e, int len, struct ast_module *module)
2617{
2618 int i, res = 0;
2619
2620 for (i = 0; i < len; i++) {
2621 res |= __ast_cli_register(e + i, module);
2622 }
2623
2624 return res;
2625}
2626
2628{
2629 int i, res = 0;
2630
2631 for (i = 0; i < len; i++)
2632 res |= ast_cli_unregister(e + i);
2633
2634 return res;
2635}
2636
2637
2638/*! \brief helper for final part of handle_help
2639 * if locked = 1, assume the list is already locked
2640 */
2641static char *help1(int fd, const char * const match[], int locked)
2642{
2643 char matchstr[80] = "";
2644 struct ast_cli_entry *e = NULL;
2645 int len = 0;
2646 int found = 0;
2647
2648 if (match) {
2649 ast_join(matchstr, sizeof(matchstr), match);
2650 len = strlen(matchstr);
2651 }
2652 if (!locked)
2654 while ( (e = cli_next(e)) ) {
2655 /* Hide commands that start with '_' */
2656 if (e->_full_cmd[0] == '_')
2657 continue;
2658 if (match && strncasecmp(matchstr, e->_full_cmd, len))
2659 continue;
2660 ast_cli(fd, "%-30s -- %s\n", e->_full_cmd,
2661 S_OR(e->summary, "<no description available>"));
2662 found++;
2663 }
2664 if (!locked)
2666 if (!found && matchstr[0])
2667 ast_cli(fd, "No such command '%s'.\n", matchstr);
2668 return CLI_SUCCESS;
2669}
2670
2671static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2672{
2673 char fullcmd[80];
2674 struct ast_cli_entry *my_e;
2675 char *res = CLI_SUCCESS;
2676
2677 if (cmd == CLI_INIT) {
2678 e->command = "core show help";
2679 e->usage =
2680 "Usage: core show help [topic]\n"
2681 " When called with a topic as an argument, displays usage\n"
2682 " information on the given command. If called without a\n"
2683 " topic, it provides a list of commands.\n";
2684 return NULL;
2685
2686 } else if (cmd == CLI_GENERATE) {
2687 /* skip first 14 or 15 chars, "core show help " */
2688 int l = strlen(a->line);
2689
2690 if (l > 15) {
2691 l = 15;
2692 }
2693 /* XXX watch out, should stop to the non-generator parts */
2694 return __ast_cli_generator(a->line + l, a->word, a->n, 0);
2695 }
2696 if (a->argc == e->args) {
2697 return help1(a->fd, NULL, 0);
2698 }
2699
2701 my_e = find_cli(a->argv + 3, 1); /* try exact match first */
2702 if (!my_e) {
2703 res = help1(a->fd, a->argv + 3, 1 /* locked */);
2705 return res;
2706 }
2707 if (my_e->usage)
2708 ast_cli(a->fd, "%s", my_e->usage);
2709 else {
2710 ast_join(fullcmd, sizeof(fullcmd), a->argv + 3);
2711 ast_cli(a->fd, "No help text available for '%s'.\n", fullcmd);
2712 }
2714 return res;
2715}
2716
2717static char *parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
2718{
2719 char *duplicate, *cur;
2720 int x = 0;
2721 int quoted = 0;
2722 int escaped = 0;
2723 int whitespace = 1;
2724 int dummy = 0;
2725
2726 if (trailingwhitespace == NULL)
2727 trailingwhitespace = &dummy;
2728 *trailingwhitespace = 0;
2729 if (s == NULL) /* invalid, though! */
2730 return NULL;
2731 /* make a copy to store the parsed string */
2732 if (!(duplicate = ast_strdup(s)))
2733 return NULL;
2734
2735 cur = duplicate;
2736
2737 /* Remove leading spaces from the command */
2738 while (isspace(*s)) {
2739 cur++;
2740 s++;
2741 }
2742
2743 /* scan the original string copying into cur when needed */
2744 for (; *s ; s++) {
2745 if (x >= max - 1) {
2746 ast_log(LOG_WARNING, "Too many arguments, truncating at %s\n", s);
2747 break;
2748 }
2749 if (*s == '"' && !escaped) {
2750 quoted = !quoted;
2751 if (quoted && whitespace) {
2752 /* start a quoted string from previous whitespace: new argument */
2753 argv[x++] = cur;
2754 whitespace = 0;
2755 }
2756 } else if ((*s == ' ' || *s == '\t') && !(quoted || escaped)) {
2757 /* If we are not already in whitespace, and not in a quoted string or
2758 processing an escape sequence, and just entered whitespace, then
2759 finalize the previous argument and remember that we are in whitespace
2760 */
2761 if (!whitespace) {
2762 *cur++ = '\0';
2763 whitespace = 1;
2764 }
2765 } else if (*s == '\\' && !escaped) {
2766 escaped = 1;
2767 } else {
2768 if (whitespace) {
2769 /* we leave whitespace, and are not quoted. So it's a new argument */
2770 argv[x++] = cur;
2771 whitespace = 0;
2772 }
2773 *cur++ = *s;
2774 escaped = 0;
2775 }
2776 }
2777 /* Null terminate */
2778 *cur++ = '\0';
2779 /* XXX put a NULL in the last argument, because some functions that take
2780 * the array may want a null-terminated array.
2781 * argc still reflects the number of non-NULL entries.
2782 */
2783 argv[x] = NULL;
2784 *argc = x;
2785 *trailingwhitespace = whitespace;
2786 return duplicate;
2787}
2788
2789char **ast_cli_completion_matches(const char *text, const char *word)
2790{
2792 char **match_list;
2793
2794 if (!vec) {
2795 return NULL;
2796 }
2797
2798 if (AST_VECTOR_APPEND(vec, NULL)) {
2799 /* We failed to NULL terminate the elements */
2802
2803 return NULL;
2804 }
2805
2806 match_list = AST_VECTOR_STEAL_ELEMENTS(vec);
2808
2809 return match_list;
2810}
2811
2812AST_THREADSTORAGE_RAW(completion_storage);
2813
2814/*!
2815 * \internal
2816 * \brief Add a value to the vector.
2817 *
2818 * \param vec Vector to add \a value to. Must be from threadstorage.
2819 * \param value The value to add.
2820 *
2821 * \retval 0 Success
2822 * \retval -1 Failure
2823 */
2825{
2826 if (!value) {
2827 return 0;
2828 }
2829
2830 if (!vec || AST_VECTOR_ADD_SORTED(vec, value, strcasecmp)) {
2831 if (vec) {
2832 ast_threadstorage_set_ptr(&completion_storage, NULL);
2833
2835 AST_VECTOR_FREE(vec);
2836 }
2837 ast_free(value);
2838
2839 return -1;
2840 }
2841
2842 return 0;
2843}
2844
2846{
2847 return cli_completion_vector_add(ast_threadstorage_get_ptr(&completion_storage), value);
2848}
2849
2850struct ast_vector_string *ast_cli_completion_vector(const char *text, const char *word)
2851{
2852 char *retstr, *prevstr;
2853 size_t max_equal;
2854 size_t which = 0;
2855 struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec));
2856
2857 /* Recursion into this function is a coding error. */
2858 ast_assert(!ast_threadstorage_get_ptr(&completion_storage));
2859
2860 if (!vec) {
2861 return NULL;
2862 }
2863
2864 if (ast_threadstorage_set_ptr(&completion_storage, vec)) {
2865 ast_log(LOG_ERROR, "Failed to initialize threadstorage for completion.\n");
2866 ast_free(vec);
2867
2868 return NULL;
2869 }
2870
2871 while ((retstr = ast_cli_generator(text, word, which)) != NULL) {
2872 if (cli_completion_vector_add(vec, retstr)) {
2873 ast_threadstorage_set_ptr(&completion_storage, NULL);
2874
2875 goto vector_cleanup;
2876 }
2877
2878 ++which;
2879 }
2880
2881 ast_threadstorage_set_ptr(&completion_storage, NULL);
2882
2883 if (!AST_VECTOR_SIZE(vec)) {
2885
2886 return NULL;
2887 }
2888
2889 prevstr = AST_VECTOR_GET(vec, 0);
2890 max_equal = strlen(prevstr);
2891 which = 1;
2892
2893 /* Find the longest substring that is common to all results
2894 * (it is a candidate for completion), and store a copy in entry 0.
2895 */
2896 while (which < AST_VECTOR_SIZE(vec)) {
2897 size_t i = 0;
2898
2899 retstr = AST_VECTOR_GET(vec, which);
2900 /* Check for and remove duplicate strings. */
2901 if (!strcasecmp(prevstr, retstr)) {
2902 AST_VECTOR_REMOVE(vec, which, 1);
2903 ast_free(retstr);
2904
2905 continue;
2906 }
2907
2908 while (i < max_equal && toupper(prevstr[i]) == toupper(retstr[i])) {
2909 i++;
2910 }
2911
2912 max_equal = i;
2913 prevstr = retstr;
2914 ++which;
2915 }
2916
2917 /* Insert longest match to position 0. */
2918 retstr = ast_strndup(AST_VECTOR_GET(vec, 0), max_equal);
2919 if (!retstr || AST_VECTOR_INSERT_AT(vec, 0, retstr)) {
2920 ast_free(retstr);
2921
2922 goto vector_cleanup;
2923 }
2924
2925 return vec;
2926
2927vector_cleanup:
2930
2931 return NULL;
2932}
2933
2934/*! \brief returns true if there are more words to match */
2935static int more_words (const char * const *dst)
2936{
2937 int i;
2938 for (i = 0; dst[i]; i++) {
2939 if (dst[i][0] != '[')
2940 return -1;
2941 }
2942 return 0;
2943}
2944
2945/*
2946 * generate the entry at position 'state'
2947 */
2948static char *__ast_cli_generator(const char *text, const char *word, int state, int lock)
2949{
2950 const char *argv[AST_MAX_ARGS];
2951 struct ast_cli_entry *e = NULL;
2952 int x = 0, argindex, matchlen;
2953 int matchnum=0;
2954 char *ret = NULL;
2955 char matchstr[80] = "";
2956 int tws = 0;
2957 /* Split the argument into an array of words */
2958 char *duplicate = parse_args(text, &x, argv, ARRAY_LEN(argv), &tws);
2959
2960 if (!duplicate) /* malloc error */
2961 return NULL;
2962
2963 /* Compute the index of the last argument (could be an empty string) */
2964 argindex = (!ast_strlen_zero(word) && x>0) ? x-1 : x;
2965
2966 /* rebuild the command, ignore terminating white space and flatten space */
2967 ast_join(matchstr, sizeof(matchstr)-1, argv);
2968 matchlen = strlen(matchstr);
2969 if (tws) {
2970 strcat(matchstr, " "); /* XXX */
2971 if (matchlen)
2972 matchlen++;
2973 }
2974 if (lock)
2976 while ( (e = cli_next(e)) ) {
2977 /* XXX repeated code */
2978 int src = 0, dst = 0, n = 0;
2979
2980 if (e->command[0] == '_')
2981 continue;
2982
2983 /*
2984 * Try to match words, up to and excluding the last word, which
2985 * is either a blank or something that we want to extend.
2986 */
2987 for (;src < argindex; dst++, src += n) {
2988 n = word_match(argv[src], e->cmda[dst]);
2989 if (n < 0)
2990 break;
2991 }
2992
2993 if (src != argindex && more_words(e->cmda + dst)) /* not a match */
2994 continue;
2995 ret = is_prefix(argv[src], e->cmda[dst], state - matchnum, &n);
2996 matchnum += n; /* this many matches here */
2997 if (ret) {
2998 /*
2999 * argv[src] is a valid prefix of the next word in this
3000 * command. If this is also the correct entry, return it.
3001 */
3002 if (matchnum > state)
3003 break;
3004 ast_free(ret);
3005 ret = NULL;
3006 } else if (ast_strlen_zero(e->cmda[dst])) {
3007 /*
3008 * This entry is a prefix of the command string entered
3009 * (only one entry in the list should have this property).
3010 * Run the generator if one is available. In any case we are done.
3011 */
3012 if (e->handler) { /* new style command */
3013 struct ast_cli_args a = {
3014 .line = matchstr, .word = word,
3015 .pos = argindex,
3016 .n = state - matchnum,
3017 .argv = argv,
3018 .argc = x};
3019
3020 /* If the command is in a module it must be running. */
3021 if (!e->module || ast_module_running_ref(e->module)) {
3022 ret = e->handler(e, CLI_GENERATE, &a);
3023 ast_module_unref(e->module);
3024 }
3025 }
3026 if (ret)
3027 break;
3028 }
3029 }
3030 if (lock)
3032 ast_free(duplicate);
3033 return ret;
3034}
3035
3036char *ast_cli_generator(const char *text, const char *word, int state)
3037{
3038 return __ast_cli_generator(text, word, state, 1);
3039}
3040
3042{
3043 int found = 0;
3044 int i;
3045
3047 for (i = 0; i < AST_VECTOR_SIZE(&shutdown_commands); ++i) {
3048 if (e == AST_VECTOR_GET(&shutdown_commands, i)) {
3049 found = 1;
3050 break;
3051 }
3052 }
3054
3055 return found;
3056}
3057
3058int ast_cli_command_full(int uid, int gid, int fd, const char *s)
3059{
3060 const char *args[AST_MAX_ARGS + 1];
3061 struct ast_cli_entry *e = NULL;
3062 int x;
3063 char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL);
3064 char tmp[AST_MAX_ARGS + 1];
3065 char *retval = CLI_FAILURE;
3066 struct ast_cli_args a = {
3067 .fd = fd, .argc = x, .argv = args+1 };
3068
3069 if (duplicate == NULL)
3070 return RESULT_FAILURE;
3071
3072 if (x < 1) /* We need at least one entry, otherwise ignore */
3073 goto done;
3074
3076 e = find_cli(args + 1, 0);
3077 if (e)
3080 if (e == NULL) {
3081 ast_cli(fd, "No such command '%s' (type 'core show help %s' for other possible commands)\n", s, find_best(args + 1));
3082 goto done;
3083 }
3084
3086 ast_cli(fd, "Command '%s' cannot be run during shutdown\n", s);
3087 goto done;
3088 }
3089
3090 ast_join(tmp, sizeof(tmp), args + 1);
3091 /* Check if the user has rights to run this command. */
3092 if (!cli_has_permissions(uid, gid, tmp)) {
3093 ast_cli(fd, "You don't have permissions to run '%s' command\n", tmp);
3094 goto done;
3095 }
3096
3097 /*
3098 * Within the handler, argv[-1] contains a pointer to the ast_cli_entry.
3099 * Remember that the array returned by parse_args is NULL-terminated.
3100 */
3101 args[0] = (char *)e;
3102
3103 /* If the command is in a module it must be running. */
3104 if (!e->module || ast_module_running_ref(e->module)) {
3105 retval = e->handler(e, CLI_HANDLER, &a);
3106 ast_module_unref(e->module);
3107 }
3108
3109 if (retval == CLI_SHOWUSAGE) {
3110 ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
3111 } else if (retval == CLI_FAILURE) {
3112 ast_cli(fd, "Command '%s' failed.\n", s);
3113 }
3114
3115done:
3116 if (e) {
3118 }
3119 ast_free(duplicate);
3120 return retval == CLI_SUCCESS ? RESULT_SUCCESS : RESULT_FAILURE;
3121}
3122
3123int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s)
3124{
3125 char cmd[512];
3126 int x, y = 0, count = 0;
3127
3128 for (x = 0; x < size; x++) {
3129 cmd[y] = s[x];
3130 y++;
3131 if (s[x] == '\0') {
3132 ast_cli_command_full(uid, gid, fd, cmd);
3133 y = 0;
3134 count++;
3135 }
3136 }
3137 return count;
3138}
3139
3140void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix)
3141{
3142 print_uptimestr(fd, ast_tv(seconds, 0), prefix, 0);
3143}
3144
3146{
3147 int res;
3148
3152
3153 return res;
3154}
Prototypes for public functions only of internal interest,.
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
void __ast_cli_register_multiple(void)
Definition ael_main.c:204
jack_status_t status
Definition app_jack.c:149
char * text
Definition app_queue.c:1791
ast_mutex_t lock
Definition app_sla.c:337
#define var
Definition ast_expr2f.c:605
char * strsep(char **str, const char *delims)
char * strcasestr(const char *, const char *)
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
int ast_shutting_down(void)
Definition asterisk.c:1889
#define ast_free(a)
Definition astmm.h:180
#define ast_strndup(str, len)
A wrapper for strndup()
Definition astmm.h:256
#define ast_realloc(p, len)
A wrapper for realloc()
Definition astmm.h:226
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_cleanup(obj)
Definition astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_MULTIPLE
Definition astobj2.h:1049
Bridging API.
int ast_cdr_serialize_variables(const char *channel_name, struct ast_str **buf, char delim, char sep)
Serializes all the data and variables for a current CDR record.
Definition cdr.c:3499
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition chan_iax2.c:2388
static int usecnt
static const char type[]
static void dummy(char *unused,...)
General Asterisk PBX channel definitions.
const char * ast_channel_linkedid(const struct ast_channel *chan)
const char * ast_channel_name(const struct ast_channel *chan)
struct ast_channel * ast_channel_callback(ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags)
Call a function with every active channel.
Definition channel.c:1335
const char * ast_channel_data(const struct ast_channel *chan)
#define DEBUGCHAN_FLAG
Definition channel.h:877
unsigned int ast_channel_fin(const struct ast_channel *chan)
struct varshead * ast_channel_varshead(struct ast_channel *chan)
const char * ast_channel_tenantid(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2982
struct ast_trans_pvt * ast_channel_readtrans(const struct ast_channel *chan)
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
struct ast_trans_pvt * ast_channel_writetrans(const struct ast_channel *chan)
ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
ast_callid ast_channel_callid(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
unsigned long global_fin
Definition channel.c:98
const char * ast_channel_appl(const struct ast_channel *chan)
struct timeval ast_channel_creationtime(struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition channel.c:1416
void ast_channel_fin_set(struct ast_channel *chan, unsigned int value)
int ast_active_channels(void)
returns number of active/allocated channels
Definition channel.c:499
unsigned int ast_channel_fout(const struct ast_channel *chan)
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
struct ast_bridge * ast_channel_get_bridge(const struct ast_channel *chan)
Get the bridge associated with a channel.
Definition channel.c:10582
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition channel.c:2461
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition channel.h:3018
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
ast_group_t ast_channel_callgroup(const struct ast_channel *chan)
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
const char * ast_channel_language(const struct ast_channel *chan)
const char * ast_state2str(enum ast_channel_state state)
Gives the string form of a given channel state.
Definition channel.c:636
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition channel.h:991
void ast_channel_fout_set(struct ast_channel *chan, unsigned int value)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
unsigned long global_fout
Definition channel.h:886
const char * ast_channel_exten(const struct ast_channel *chan)
@ AST_SOFTHANGUP_EXPLICIT
Definition channel.h:1168
#define ast_channel_unlock(chan)
Definition channel.h:2983
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
ast_channel_state
ast_channel states
const char * ast_var_name(const struct ast_var_t *var)
Definition chanvars.c:60
const char * ast_var_value(const struct ast_var_t *var)
Definition chanvars.c:80
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define AST_CLI_COMPLETE_EOF
Definition cli.h:52
#define CLI_NO_PERMS
Definition cli.h:38
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
#define AST_MAX_ARGS
Definition cli.h:50
#define RESULT_SUCCESS
Definition cli.h:40
#define ESS(x)
Definition cli.h:59
@ CLI_HANDLER
Definition cli.h:154
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define CLI_FAILURE
Definition cli.h:46
#define AST_MAX_CMD_LEN
Definition cli.h:48
#define RESULT_FAILURE
Definition cli.h:42
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition codec.c:348
static struct channel_usage channels
short word
char buf[BUFSIZE]
Definition eagi_proxy.c:66
#define min(a, b)
Definition f2c.h:197
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
#define AST_FORMAT_CAP_NAMES_LEN
Definition format_cap.h:324
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition format_cap.c:734
static const char name[]
Definition format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
unsigned int ast_trace_get_by_module(const char *module)
Get the trace level for a module.
Definition main/cli.c:156
struct ao2_container * ast_channel_cache_all(void)
struct ao2_container * ast_channel_cache_by_name(void)
Secondary channel cache, indexed by name.
int option_debug
Definition options.c:70
int ast_option_maxcalls
Definition options.c:80
struct ast_flags64 ast_options
Definition options.c:62
int option_trace
Definition options.c:72
@ AST_OPT_FLAG_TRACE_MODULE
Definition options.h:89
@ AST_OPT_FLAG_DEBUG_MODULE
Definition options.h:87
static char prefix[MAX_PREFIX]
Definition http.c:144
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
int ast_app_group_list_unlock(void)
Unlock the group count list.
Definition main/app.c:2351
struct ast_group_info * ast_app_group_list_head(void)
Get the head of the group count list.
Definition main/app.c:2346
int ast_app_group_list_rdlock(void)
Read Lock the group count list.
Definition main/app.c:2341
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition extconf.c:3324
#define CONFIG_STATUS_FILEUNCHANGED
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
@ CONFIG_FLAG_FILEUNCHANGED
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213
void ast_callid_strnprint(char *buffer, size_t buffer_size, ast_callid callid)
copy a string representation of the callid into a target string
Definition logger.c:2258
void ast_console_toggle_mute(int fd, int silent)
mute or unmute a console from logging
Definition asterisk.c:1287
unsigned int ast_callid
#define LOG_ERROR
#define LOG_NOTICE
#define LOG_WARNING
int ast_verb_console_get(void)
Get this thread's console verbosity level.
Definition logger.c:2643
void ast_verb_console_set(int verb_level)
Set this thread's console verbosity level.
Definition logger.c:2661
A set of macros to manage forward-linked lists.
#define AST_RWLIST_EMPTY
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition linkedlists.h:78
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
#define AST_RWLIST_REMOVE_HEAD
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_RWLIST_REMOVE
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_RWLIST_TRAVERSE_SAFE_END
#define AST_RWLIST_HEAD(name, type)
Defines a structure to be used to hold a read/write list of specified type.
#define AST_RWLIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_RWLIST_HEAD.
#define AST_RWLIST_INSERT_TAIL
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_RWLIST_ENTRY
#define AST_RWLIST_INSERT_BEFORE_CURRENT
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Asterisk locking-related definitions:
#define ast_rwlock_wrlock(a)
Definition lock.h:243
#define ast_rwlock_rdlock(a)
Definition lock.h:242
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition lock.h:550
#define ast_mutex_unlock(a)
Definition lock.h:197
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition lock.h:764
#define ast_mutex_trylock(a)
Definition lock.h:198
#define ast_rwlock_unlock(a)
Definition lock.h:241
#define ast_mutex_lock(a)
Definition lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
#define AST_LOG_CATEGORY_DISABLED
#define AST_LOG_CATEGORY_ENABLED
char * ast_debug_category_complete(const char *const *argv, int argc, const char *word, int state)
Add a unique (no duplicates) result to a request for completion for debug categories.
int ast_debug_category_set_sublevels(const char *const *names, size_t size, int default_sublevel)
Set one or more debug category's sublevel.
#define VERBOSE_HANDLER
Definition main/cli.c:408
static char * handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1723
#define TRACE_HANDLER
Definition main/cli.c:407
#define arg_looks_like_glob(n)
Definition main/cli.c:1285
static void remove_shutdown_command(struct ast_cli_entry *e)
Definition main/cli.c:2509
void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix)
Print on cli a duration in seconds in format s year(s), s week(s), s day(s), s hour(s),...
Definition main/cli.c:3140
static char * handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1107
static ast_rwlock_t shutdown_commands_lock
Definition main/cli.c:113
void ast_cli_channels_init(void)
Definition main/cli.c:2329
char * ast_cli_generator(const char *text, const char *word, int state)
Readline madness Useful for readline, that's about it.
Definition main/cli.c:3036
static void cli_shutdown(void)
Definition main/cli.c:2311
static char * handle_debug_or_trace(int handler, struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:452
static char * handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:271
size_t max
Definition main/cli.c:114
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition main/cli.c:2516
#define AST_CLI_INITLEN
Initial buffer size for resulting strings in ast_cli()
Definition main/cli.c:117
static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
Definition main/cli.c:916
static char * handle_cli_reload_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handles CLI command 'cli reload permissions'
Definition main/cli.c:1440
static struct ast_cli_entry * find_cli(const char *const cmds[], int match_type)
Definition main/cli.c:2435
static void cli_channels_shutdown(void)
Definition main/cli.c:2316
#define arg_looks_like_regex(n)
Definition main/cli.c:1282
static int modlist_modentry(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level)
Definition main/cli.c:903
static int channel_set_debug(void *obj, void *arg, void *data, int flags)
Definition main/cli.c:1595
#define FORMAT_STRING
#define HOUR
#define MAX_REGEX_ERROR_LEN
Definition main/cli.c:119
static int set_full_cmd(struct ast_cli_entry *e)
Definition main/cli.c:2154
#define WEEK
static struct ast_cli_entry cli_cli[]
Definition main/cli.c:2104
#define DAY
static char * handle_trace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:633
static char * find_best(const char *argv[])
Definition main/cli.c:2479
static char * group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1985
#define YEAR
static struct module_level_list debug_modules
Definition main/cli.c:108
static char * handle_cli_show_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handles CLI command 'cli show permissions'
Definition main/cli.c:1395
static struct module_level_list trace_modules
Definition main/cli.c:109
#define DEBUG_HANDLER
Definition main/cli.c:406
#define NEEDCOMMA(x)
static char * handle_logger_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:786
static char * handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1536
static ast_mutex_t permsconfiglock
mutex used to prevent a user from running the 'cli reload permissions' command while it is already ru...
Definition main/cli.c:92
static char * handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:243
#define VERBOSE_FORMAT_STRING2
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition main/cli.c:2845
static char * handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1051
void ast_cli(int fd, const char *fmt,...)
Definition main/cli.c:121
static struct @355 shutdown_commands
static char * handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1011
int __ast_cli_register(struct ast_cli_entry *e, struct ast_module *module)
Definition main/cli.c:2539
static int word_match(const char *cmd, const char *cli_word)
Definition main/cli.c:2346
static int allowed_on_shutdown(struct ast_cli_entry *e)
Definition main/cli.c:3041
static char * handle_refresh(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:811
#define CONCISE_FORMAT_STRING
static char * complete_number(const char *partial, unsigned int min, unsigned int max, int n)
Definition main/cli.c:366
static char * help1(int fd, const char *const match[], int locked)
helper for final part of handle_help if locked = 1, assume the list is already locked
Definition main/cli.c:2641
static char * handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:848
static const char cli_rsvd[]
Definition main/cli.c:2148
static int cli_default_perm
Default permissions value 1=Permit 0=Deny.
Definition main/cli.c:88
static char * handle_cli_check_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handles CLI command 'cli check permissions'
Definition main/cli.c:1459
char * ast_cli_complete(const char *word, const char *const choices[], int state)
Definition main/cli.c:1931
char ** ast_cli_completion_matches(const char *text, const char *word)
Generates a NULL-terminated array of strings that 1) begin with the string in the second parameter,...
Definition main/cli.c:2789
static char * handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:2671
static int more_words(const char *const *dst)
returns true if there are more words to match
Definition main/cli.c:2935
static struct ast_cli_entry cli_channels_cli[]
Definition main/cli.c:2136
static int cli_has_permissions(int uid, int gid, const char *command)
Definition main/cli.c:186
#define MODLIST_FORMAT
Definition main/cli.c:897
int ast_cli_allow_at_shutdown(struct ast_cli_entry *e)
Allow a CLI command to be executed while Asterisk is shutting down.
Definition main/cli.c:3145
char * ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
Command completion for the list of active channels.
Definition main/cli.c:1950
static void destroy_user_perms(void)
cleanup (free) cli_perms linkedlist.
Definition main/cli.c:2173
void ast_builtins_init(void)
initialize the _full_cmd string in * each of the builtins.
Definition main/cli.c:2322
static int cli_completion_vector_add(struct ast_vector_string *vec, char *value)
Definition main/cli.c:2824
static int climodentryfd
Definition main/cli.c:901
static char * handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1288
static char * handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1619
static char * handle_cli_malloc_trim(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:2076
int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s)
Executes multiple CLI commands Interpret strings separated by NULL and execute each one,...
Definition main/cli.c:3123
static char * handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:2039
#define MODLIST_FORMAT2
Definition main/cli.c:898
static void status_debug_verbose(struct ast_cli_args *a, int handler, int old_val, int cur_val)
Definition main/cli.c:410
static char * handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:322
static char * is_prefix(const char *word, const char *token, int pos, int *actual)
if word is a valid prefix for token, returns the pos-th match as a malloced string,...
Definition main/cli.c:2385
static char * handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:575
struct ast_vector_string * ast_cli_completion_vector(const char *text, const char *word)
Generates a vector of strings for CLI completion.
Definition main/cli.c:2850
#define MINUTE
static ast_mutex_t climodentrylock
Definition main/cli.c:900
static struct ast_cli_entry * cli_next(struct ast_cli_entry *e)
Definition main/cli.c:969
static char * __ast_cli_generator(const char *text, const char *word, int state, int lock)
Definition main/cli.c:2948
static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:978
static char * parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
Definition main/cli.c:2717
static int cli_is_registered(struct ast_cli_entry *e)
Definition main/cli.c:2497
static struct module_level * find_module_level(const char *module, struct module_level_list *mll)
Find the module level setting.
Definition main/cli.c:354
int ast_cli_perms_init(int reload)
Definition main/cli.c:2189
#define FORMAT_STRING2
static const char perms_config[]
CLI permissions config file.
Definition main/cli.c:86
static char * handle_debug_category(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:1682
unsigned int ast_debug_get_by_module(const char *module)
Get the debug level for a module.
Definition main/cli.c:139
static char * handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition main/cli.c:686
int ast_cli_command_full(int uid, int gid, int fd, const char *s)
Interprets a command Interpret a command s, sending output to fd if uid:gid has permissions to run th...
Definition main/cli.c:3058
static int channel_match_by_regex(const char *channel_name, const void *data)
Definition main/cli.c:1233
#define VERBOSE_FORMAT_STRING
static int channel_hangup_matches(struct ast_cli_args *a, int(*matchfn)(const char *, const void *), const void *data)
Definition main/cli.c:1253
static int channel_match_by_glob(const char *channel_name, const void *pattern)
Definition main/cli.c:1238
Asterisk module definitions.
int ast_update_module_list(int(*modentry)(const char *module, const char *description, int usecnt, const char *status, const char *like, enum ast_module_support_level support_level), const char *like)
Ask for a list of modules, descriptions, use counts and status.
Definition loader.c:2746
#define ast_module_unref(mod)
Release a reference to the module.
Definition module.h:483
const char * ast_module_support_level_to_string(enum ast_module_support_level support_level)
Definition loader.c:2934
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode)
Unload a module.
Definition loader.c:1457
char * ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
Match modules names for the Asterisk cli.
Definition loader.c:1537
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition loader.c:1987
int ast_refresh_resource(const char *resource_name, enum ast_module_unload_mode force, int recursive)
Unload and load a module again.
Definition loader.c:1416
ast_module_support_level
Definition module.h:119
@ AST_FORCE_SOFT
Definition module.h:62
@ AST_FORCE_HARD
Definition module.h:64
@ AST_FORCE_FIRM
Definition module.h:63
ast_module_reload_result
Possible return types for ast_module_reload.
Definition module.h:109
@ AST_MODULE_RELOAD_IN_PROGRESS
Definition module.h:114
@ AST_MODULE_RELOAD_QUEUED
Definition module.h:111
@ AST_MODULE_RELOAD_SUCCESS
Definition module.h:110
@ AST_MODULE_RELOAD_ERROR
Definition module.h:113
@ AST_MODULE_RELOAD_NOT_IMPLEMENTED
Definition module.h:116
@ AST_MODULE_RELOAD_NOT_FOUND
Definition module.h:112
@ AST_MODULE_RELOAD_UNINITIALIZED
Definition module.h:115
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition module.h:469
@ AST_MODULE_HELPER_RELOAD
Definition module.h:131
@ AST_MODULE_HELPER_LOADED
Definition module.h:129
@ AST_MODULE_HELPER_UNLOAD
Definition module.h:135
@ AST_MODULE_HELPER_LOAD
Definition module.h:133
@ AST_MODULE_HELPER_RUNNING
Definition module.h:137
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition loader.c:1730
#define ast_fully_booted
Definition options.h:127
struct timeval ast_lastreloadtime
Definition asterisk.c:345
struct timeval ast_startuptime
Definition asterisk.c:344
Asterisk file paths, configured in asterisk.conf.
Core PBX routines and definitions.
int ast_active_calls(void)
Retrieve the number of active calls.
Definition pbx.c:4781
int ast_processed_calls(void)
Retrieve the total number of calls processed through the PBX since last restart.
Definition pbx.c:4786
static int reload(void)
static struct @522 args
#define NULL
Definition resample.c:96
Media Stream API.
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition stream.c:309
const char * ast_stream_state2str(enum ast_stream_state state)
Convert the state of a stream into a string.
Definition stream.c:388
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int position)
Get a specific stream from the topology.
Definition stream.c:791
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition stream.c:768
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition stream.c:373
int ast_stream_get_group(const struct ast_stream *stream)
Get the stream group that a stream is part of.
Definition stream.c:1080
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition stream.c:316
struct ast_variable * ast_stream_get_metadata_list(const struct ast_stream *stream)
Get all stream metadata keys.
Definition stream.c:439
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
Definition stream.c:330
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition strings.h:1321
int ast_str_set_va(struct ast_str **buf, ssize_t max_len, const char *fmt, va_list ap)
Set a dynamic string from a va_list.
Definition strings.h:1030
size_t attribute_pure ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition strings.h:730
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char *attribute_pure ast_skip_nonblanks(const char *str)
Gets a pointer to first whitespace character in a string.
Definition strings.h:204
@ AST_DYNSTR_BUILD_FAILED
Definition strings.h:943
#define ast_str_alloca(init_len)
Definition strings.h:848
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
#define ast_join(s, len, w)
Join an array of strings into a single string.
Definition strings.h:520
char *attribute_pure ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition strings.h:161
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition strings.h:909
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
Structure that contains information about a bridge.
Definition bridge.h:353
ast_callid callid
Definition bridge.h:365
const ast_string_field uniqueid
Definition bridge.h:405
const ast_string_field accountcode
const ast_string_field uniqueid
const ast_string_field name
const ast_string_field number
const ast_string_field data
const ast_string_field context
const ast_string_field exten
const ast_string_field appl
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_dialplan * dialplan
struct ast_channel_snapshot_peer * peer
struct ast_channel_snapshot_bridge * bridge
struct ast_channel_snapshot_base * base
enum ast_channel_state state
struct ast_channel_snapshot_caller * caller
Structure to describe a channel "technology", ie a channel driver See for examples:
Definition channel.h:648
Main Channel structure associated with a channel.
struct ast_channel_snapshot * snapshot
const char * data
const int fd
Definition cli.h:159
const char *const * argv
Definition cli.h:161
descriptor for a cli entry.
Definition cli.h:171
int args
This gets set in ast_cli_register()
Definition cli.h:185
char *(* handler)(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition cli.h:187
int cmdlen
Definition cli.h:182
const char *const summary
Definition cli.h:176
int inuse
Definition cli.h:179
struct ast_module *char * _full_cmd
Definition cli.h:180
struct ast_cli_entry::@225 list
const char *const cmda[AST_MAX_CMD_LEN]
Definition cli.h:172
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
Structure used to handle boolean flags.
Definition utils.h:220
channel group info
Definition channel.h:2975
char * category
Definition channel.h:2977
struct ast_group_info::@223 group_list
struct ast_channel * chan
Definition channel.h:2976
Support for dynamic strings.
Definition strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
String vector definitions.
Definition vector.h:55
List of restrictions per user.
Definition main/cli.c:70
struct cli_perm::@356 list
unsigned int permit
Definition main/cli.c:71
char * command
Definition main/cli.c:72
List of users and permissions.
Definition main/cli.c:94
map a debug or verbose level to a module name
Definition main/cli.c:99
struct module_level * next
Definition main/cli.c:101
unsigned int level
Definition main/cli.c:100
struct module_level::@358 entry
char module[0]
Definition main/cli.c:102
Number structure.
list of users to apply restrictions.
Definition main/cli.c:79
struct cli_perm_head * perms
Definition main/cli.c:82
struct usergroup_cli_perm::@357 list
int value
Definition syslog.c:37
int done
static void handler(const char *name, int response_code, struct ast_variable *get_params, struct ast_variable *path_vars, struct ast_variable *headers, struct ast_json *body, struct ast_ari_response *response)
Definition test_ari.c:59
static struct test_val a
static struct test_val c
Definitions to aid in the use of thread local storage.
int ast_threadstorage_set_ptr(struct ast_threadstorage *ts, void *ptr)
Set a raw pointer from threadstorage.
void * ast_threadstorage_get_ptr(struct ast_threadstorage *ts)
Retrieve a raw pointer from threadstorage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
#define AST_THREADSTORAGE_RAW(name)
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition time.h:117
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition extconf.c:2295
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition time.h:235
Support for translation of data formats. translate.c.
const char * ast_translate_path_to_str(struct ast_trans_pvt *t, struct ast_str **str)
Puts a string representation of the translation path into outbuf.
Definition translate.c:930
FILE * out
Definition utils/frame.c:33
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition utils.h:981
#define ast_assert(a)
Definition utils.h:779
#define ast_clear_flag64(p, flag)
Definition utils.h:154
int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
Try to write string, but wait no more than ms milliseconds before timing out.
Definition utils.c:1807
#define ast_set_flag64(p, flag)
Definition utils.h:147
#define ARRAY_LEN(a)
Definition utils.h:706
Vector container support.
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition vector.h:582
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_INSERT_AT(vec, idx, elem)
Insert an element at a specific position in a vector, growing the vector if needed.
Definition vector.h:349
#define AST_VECTOR_STEAL_ELEMENTS(vec)
Steal the elements from a vector and reinitialize.
Definition vector.h:151
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_REMOVE_ELEM_UNORDERED(vec, elem, cleanup)
Remove an element from a vector.
Definition vector.h:594
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition vector.h:382
#define AST_VECTOR_REMOVE(vec, idx, preserve_ordered)
Remove an element from a vector by index.
Definition vector.h:423
#define AST_VECTOR_PTR_FREE(vec)
Deallocates this vector pointer.
Definition vector.h:200
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition vector.h:873
#define AST_VECTOR(name, type)
Define a vector structure.
Definition vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691