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