Asterisk - The Open Source Telephony Project  GIT-master-a24979a
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"
50 #include "asterisk/linkedlists.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"
57 #include "asterisk/threadstorage.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  */
69 struct 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. */
85 static const char perms_config[] = "cli_permissions.conf";
86 /*! \brief Default permissions value 1=Permit 0=Deny */
87 static 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  */
98 struct module_level {
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 
118 void 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 
136 unsigned 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 
153 unsigned 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  */
183 static 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 
240 static 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 
268 static 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 
319 static 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  */
351 static 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 
363 static 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 
407 static 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 
449 static 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 
572 static 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 
630 static 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 
683 static 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 
783 static 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"))
801  ast_console_toggle_mute(a->fd, 1);
802  else
803  ast_console_toggle_mute(a->fd, 0);
804 
805  return CLI_SUCCESS;
806 }
807 
808 static char *handle_refresh(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
809 {
810  /* "module refresh <mod>" */
811  switch (cmd) {
812  case CLI_INIT:
813  e->command = "module refresh";
814  e->usage =
815  "Usage: module refresh <module name>\n"
816  " Unloads and loads the specified module into Asterisk.\n";
817  return NULL;
818 
819  case CLI_GENERATE:
820  if (a->pos != e->args) {
821  return NULL;
822  }
823  return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_UNLOAD);
824  }
825  if (a->argc != e->args + 1) {
826  return CLI_SHOWUSAGE;
827  }
828  if (ast_unload_resource(a->argv[e->args], AST_FORCE_SOFT)) {
829  ast_cli(a->fd, "Unable to unload resource %s\n", a->argv[e->args]);
830  return CLI_FAILURE;
831  }
832  if (ast_load_resource(a->argv[e->args])) {
833  ast_cli(a->fd, "Unable to load module %s\n", a->argv[e->args]);
834  return CLI_FAILURE;
835  }
836  ast_cli(a->fd, "Unloaded and loaded %s\n", a->argv[e->args]);
837  return CLI_SUCCESS;
838 }
839 
840 static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
841 {
842  /* "module unload mod_1 [mod_2 .. mod_N]" */
843  int x;
844  int force = AST_FORCE_SOFT;
845  const char *s;
846 
847  switch (cmd) {
848  case CLI_INIT:
849  e->command = "module unload";
850  e->usage =
851  "Usage: module unload [-f|-h] <module_1> [<module_2> ... ]\n"
852  " Unloads the specified module from Asterisk. The -f\n"
853  " option causes the module to be unloaded even if it is\n"
854  " in use (may cause a crash) and the -h module causes the\n"
855  " module to be unloaded even if the module says it cannot, \n"
856  " which almost always will cause a crash.\n";
857  return NULL;
858 
859  case CLI_GENERATE:
860  return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_UNLOAD);
861  }
862  if (a->argc < e->args + 1)
863  return CLI_SHOWUSAGE;
864  x = e->args; /* first argument */
865  s = a->argv[x];
866  if (s[0] == '-') {
867  if (s[1] == 'f')
868  force = AST_FORCE_FIRM;
869  else if (s[1] == 'h')
870  force = AST_FORCE_HARD;
871  else
872  return CLI_SHOWUSAGE;
873  if (a->argc < e->args + 2) /* need at least one module name */
874  return CLI_SHOWUSAGE;
875  x++; /* skip this argument */
876  }
877 
878  for (; x < a->argc; x++) {
879  if (ast_unload_resource(a->argv[x], force)) {
880  ast_cli(a->fd, "Unable to unload resource %s\n", a->argv[x]);
881  return CLI_FAILURE;
882  }
883  ast_cli(a->fd, "Unloaded %s\n", a->argv[x]);
884  }
885 
886  return CLI_SUCCESS;
887 }
888 
889 #define MODLIST_FORMAT "%-30s %-40.40s %-10d %-11s %13s\n"
890 #define MODLIST_FORMAT2 "%-30s %-40.40s %-10s %-11s %13s\n"
891 
893 static int climodentryfd = -1;
894 
895 static int modlist_modentry(const char *module, const char *description,
896  int usecnt, const char *status, const char *like,
897  enum ast_module_support_level support_level)
898 {
899  /* Comparing the like with the module */
900  if (strcasestr(module, like) ) {
901  ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt,
903  return 1;
904  }
905  return 0;
906 }
907 
908 static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
909 {
910  int x; /* the main part - years, weeks, etc. */
911  struct ast_str *out;
912 
913 #define SECOND (1)
914 #define MINUTE (SECOND*60)
915 #define HOUR (MINUTE*60)
916 #define DAY (HOUR*24)
917 #define WEEK (DAY*7)
918 #define YEAR (DAY*365)
919 #define NEEDCOMMA(x) ((x) ? ", " : "") /* define if we need a comma */
920  if (timeval.tv_sec < 0) /* invalid, nothing to show */
921  return;
922 
923  if (printsec) { /* plain seconds output */
924  ast_cli(fd, "%s%lu\n", prefix, (u_long)timeval.tv_sec);
925  return;
926  }
927  out = ast_str_alloca(256);
928  if (timeval.tv_sec > YEAR) {
929  x = (timeval.tv_sec / YEAR);
930  timeval.tv_sec -= (x * YEAR);
931  ast_str_append(&out, 0, "%d year%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
932  }
933  if (timeval.tv_sec > WEEK) {
934  x = (timeval.tv_sec / WEEK);
935  timeval.tv_sec -= (x * WEEK);
936  ast_str_append(&out, 0, "%d week%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
937  }
938  if (timeval.tv_sec > DAY) {
939  x = (timeval.tv_sec / DAY);
940  timeval.tv_sec -= (x * DAY);
941  ast_str_append(&out, 0, "%d day%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
942  }
943  if (timeval.tv_sec > HOUR) {
944  x = (timeval.tv_sec / HOUR);
945  timeval.tv_sec -= (x * HOUR);
946  ast_str_append(&out, 0, "%d hour%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
947  }
948  if (timeval.tv_sec > MINUTE) {
949  x = (timeval.tv_sec / MINUTE);
950  timeval.tv_sec -= (x * MINUTE);
951  ast_str_append(&out, 0, "%d minute%s%s", x, ESS(x), NEEDCOMMA(timeval.tv_sec));
952  }
953  x = timeval.tv_sec;
954  if (x > 0 || ast_str_strlen(out) == 0) {
955  /* if there is nothing, print 0 seconds */
956  ast_str_append(&out, 0, "%d second%s", x, ESS(x));
957  }
958  ast_cli(fd, "%s%s\n", prefix, ast_str_buffer(out));
959 }
960 
961 static struct ast_cli_entry *cli_next(struct ast_cli_entry *e)
962 {
963  if (e) {
964  return AST_LIST_NEXT(e, list);
965  } else {
966  return AST_LIST_FIRST(&helpers);
967  }
968 }
969 
970 static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
971 {
972  struct timeval curtime = ast_tvnow();
973  int printsec;
974 
975  switch (cmd) {
976  case CLI_INIT:
977  e->command = "core show uptime [seconds]";
978  e->usage =
979  "Usage: core show uptime [seconds]\n"
980  " Shows Asterisk uptime information.\n"
981  " The seconds word returns the uptime in seconds only.\n";
982  return NULL;
983 
984  case CLI_GENERATE:
985  return NULL;
986  }
987  /* regular handler */
988  if (a->argc == e->args && !strcasecmp(a->argv[e->args-1],"seconds"))
989  printsec = 1;
990  else if (a->argc == e->args-1)
991  printsec = 0;
992  else
993  return CLI_SHOWUSAGE;
994  if (ast_startuptime.tv_sec) {
995  print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime: ", printsec);
996  }
997  if (ast_lastreloadtime.tv_sec) {
998  print_uptimestr(a->fd, ast_tvsub(curtime, ast_lastreloadtime), "Last reload: ", printsec);
999  }
1000  return CLI_SUCCESS;
1001 }
1002 
1003 static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1004 {
1005  const char *like;
1006 
1007  switch (cmd) {
1008  case CLI_INIT:
1009  e->command = "module show [like]";
1010  e->usage =
1011  "Usage: module show [like keyword]\n"
1012  " Shows Asterisk modules currently in use, and usage statistics.\n";
1013  return NULL;
1014 
1015  case CLI_GENERATE:
1016  if (a->pos == e->args) {
1017  return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, AST_MODULE_HELPER_LOADED);
1018  } else {
1019  return NULL;
1020  }
1021  }
1022  /* all the above return, so we proceed with the handler.
1023  * we are guaranteed to have argc >= e->args
1024  */
1025  if (a->argc == e->args - 1)
1026  like = "";
1027  else if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args-1], "like") )
1028  like = a->argv[e->args];
1029  else
1030  return CLI_SHOWUSAGE;
1031 
1033  climodentryfd = a->fd; /* global, protected by climodentrylock */
1034  ast_cli(a->fd, MODLIST_FORMAT2, "Module", "Description", "Use Count", "Status", "Support Level");
1035  ast_cli(a->fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
1036  climodentryfd = -1;
1038  return CLI_SUCCESS;
1039 }
1040 #undef MODLIST_FORMAT
1041 #undef MODLIST_FORMAT2
1042 
1043 static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1044 {
1045  static const char * const completions[] = { "seconds", NULL };
1046  struct timeval curtime = ast_tvnow();
1047  int showuptime, printsec;
1048 
1049  switch (cmd) {
1050  case CLI_INIT:
1051  e->command = "core show calls [uptime]";
1052  e->usage =
1053  "Usage: core show calls [uptime [seconds]]\n"
1054  " Lists number of currently active calls and total number of calls\n"
1055  " processed through PBX since last restart. If 'uptime' is specified\n"
1056  " the system uptime is also displayed. If 'seconds' is specified in\n"
1057  " addition to 'uptime', the system uptime is displayed in seconds.\n";
1058  return NULL;
1059 
1060  case CLI_GENERATE:
1061  if (a->pos != e->args)
1062  return NULL;
1063  return ast_cli_complete(a->word, completions, a->n);
1064  }
1065 
1066  /* regular handler */
1067  if (a->argc >= e->args && !strcasecmp(a->argv[e->args-1],"uptime")) {
1068  showuptime = 1;
1069 
1070  if (a->argc == e->args+1 && !strcasecmp(a->argv[e->args],"seconds"))
1071  printsec = 1;
1072  else if (a->argc == e->args)
1073  printsec = 0;
1074  else
1075  return CLI_SHOWUSAGE;
1076  } else if (a->argc == e->args-1) {
1077  showuptime = 0;
1078  printsec = 0;
1079  } else
1080  return CLI_SHOWUSAGE;
1081 
1082  if (ast_option_maxcalls) {
1083  ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
1085  ((double)ast_active_calls() / (double)ast_option_maxcalls) * 100.0);
1086  } else {
1087  ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
1088  }
1089 
1090  ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
1091 
1092  if (ast_startuptime.tv_sec && showuptime) {
1093  print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime: ", printsec);
1094  }
1095 
1096  return RESULT_SUCCESS;
1097 }
1098 
1099 static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1100 {
1101 #define FORMAT_STRING "%-20.20s %-20.20s %-7.7s %-30.30s\n"
1102 #define FORMAT_STRING2 "%-20.20s %-20.20s %-7.7s %-30.30s\n"
1103 #define CONCISE_FORMAT_STRING "%s!%s!%s!%d!%s!%s!%s!%s!%s!%s!%d!%s!%s!%s\n"
1104 #define VERBOSE_FORMAT_STRING "%-20.20s %-20.20s %-16.16s %4d %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
1105 #define VERBOSE_FORMAT_STRING2 "%-20.20s %-20.20s %-16.16s %-4.4s %-7.7s %-12.12s %-25.25s %-15.15s %8.8s %-11.11s %-11.11s %-20.20s\n"
1106 
1107  struct ao2_container *channels;
1108  struct ao2_iterator it_chans;
1109  struct ast_channel_snapshot *cs;
1110  int numchans = 0, concise = 0, verbose = 0, count = 0;
1111 
1112  switch (cmd) {
1113  case CLI_INIT:
1114  e->command = "core show channels [concise|verbose|count]";
1115  e->usage =
1116  "Usage: core show channels [concise|verbose|count]\n"
1117  " Lists currently defined channels and some information about them. If\n"
1118  " 'concise' is specified, the format is abridged and in a more easily\n"
1119  " machine parsable format. If 'verbose' is specified, the output includes\n"
1120  " more and longer fields. If 'count' is specified only the channel and call\n"
1121  " count is output.\n"
1122  " The 'concise' option is deprecated and will be removed from future versions\n"
1123  " of Asterisk.\n";
1124  return NULL;
1125 
1126  case CLI_GENERATE:
1127  return NULL;
1128  }
1129 
1130  if (a->argc == e->args) {
1131  if (!strcasecmp(a->argv[e->args-1],"concise"))
1132  concise = 1;
1133  else if (!strcasecmp(a->argv[e->args-1],"verbose"))
1134  verbose = 1;
1135  else if (!strcasecmp(a->argv[e->args-1],"count"))
1136  count = 1;
1137  else
1138  return CLI_SHOWUSAGE;
1139  } else if (a->argc != e->args - 1)
1140  return CLI_SHOWUSAGE;
1141 
1143 
1144  if (!count) {
1145  if (!concise && !verbose)
1146  ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
1147  else if (verbose)
1148  ast_cli(a->fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
1149  "CallerID", "Duration", "Accountcode", "PeerAccount", "BridgeID");
1150  }
1151 
1152  it_chans = ao2_iterator_init(channels, 0);
1153  for (; (cs = ao2_iterator_next(&it_chans)); ao2_ref(cs, -1)) {
1154  char durbuf[16] = "-";
1155 
1156  if (!count) {
1157  if ((concise || verbose) && !ast_tvzero(cs->base->creationtime)) {
1158  int duration = (int)(ast_tvdiff_ms(ast_tvnow(), cs->base->creationtime) / 1000);
1159  if (verbose) {
1160  int durh = duration / 3600;
1161  int durm = (duration % 3600) / 60;
1162  int durs = duration % 60;
1163  snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
1164  } else {
1165  snprintf(durbuf, sizeof(durbuf), "%d", duration);
1166  }
1167  }
1168  if (concise) {
1170  S_OR(cs->dialplan->appl, "(None)"),
1171  cs->dialplan->data,
1172  cs->caller->number,
1173  cs->base->accountcode,
1174  cs->peer->account,
1175  cs->amaflags,
1176  durbuf,
1177  cs->bridge->id,
1178  cs->base->uniqueid);
1179  } else if (verbose) {
1181  S_OR(cs->dialplan->appl, "(None)"),
1182  S_OR(cs->dialplan->data, "(Empty)"),
1183  cs->caller->number,
1184  durbuf,
1185  cs->base->accountcode,
1186  cs->peer->account,
1187  cs->bridge->id);
1188  } else {
1189  char locbuf[40] = "(None)";
1190  char appdata[40] = "(None)";
1191 
1193  snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", cs->dialplan->exten, cs->dialplan->context, cs->dialplan->priority);
1194  }
1195  if (!ast_strlen_zero(cs->dialplan->appl)) {
1196  snprintf(appdata, sizeof(appdata), "%s(%s)", cs->dialplan->appl, S_OR(cs->dialplan->data, ""));
1197  }
1198  ast_cli(a->fd, FORMAT_STRING, cs->base->name, locbuf, ast_state2str(cs->state), appdata);
1199  }
1200  }
1201  }
1202  ao2_iterator_destroy(&it_chans);
1203 
1204  if (!concise) {
1205  numchans = ast_active_channels();
1206  ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
1207  if (ast_option_maxcalls)
1208  ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
1210  ((double)ast_active_calls() / (double)ast_option_maxcalls) * 100.0);
1211  else
1212  ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
1213 
1214  ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
1215  }
1216  ao2_ref(channels, -1);
1217 
1218  return CLI_SUCCESS;
1219 
1220 #undef FORMAT_STRING
1221 #undef FORMAT_STRING2
1222 #undef CONCISE_FORMAT_STRING
1223 #undef VERBOSE_FORMAT_STRING
1224 #undef VERBOSE_FORMAT_STRING2
1225 }
1226 
1227 static char *handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1228 {
1229  struct ast_channel *c = NULL;
1230  static const char * const completions[] = { "all", NULL };
1231  char *complete;
1232 
1233  switch (cmd) {
1234  case CLI_INIT:
1235  e->command = "channel request hangup";
1236  e->usage =
1237  "Usage: channel request hangup <channel>|<all>\n"
1238  " Request that a channel be hung up. The hangup takes effect\n"
1239  " the next time the driver reads or writes from the channel.\n"
1240  " If 'all' is specified instead of a channel name, all channels\n"
1241  " will see the hangup request.\n";
1242  return NULL;
1243  case CLI_GENERATE:
1244  if (a->pos != e->args) {
1245  return NULL;
1246  }
1247  complete = ast_cli_complete(a->word, completions, a->n);
1248  if (!complete) {
1249  complete = ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args);
1250  }
1251  return complete;
1252  }
1253 
1254  if (a->argc != 4) {
1255  return CLI_SHOWUSAGE;
1256  }
1257 
1258  if (!strcasecmp(a->argv[3], "all")) {
1259  struct ast_channel_iterator *iter = NULL;
1260  if (!(iter = ast_channel_iterator_all_new())) {
1261  return CLI_FAILURE;
1262  }
1263  for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
1265  ast_cli(a->fd, "Requested Hangup on channel '%s'\n", ast_channel_name(c));
1268  }
1270  } else if ((c = ast_channel_get_by_name(a->argv[3]))) {
1272  ast_cli(a->fd, "Requested Hangup on channel '%s'\n", ast_channel_name(c));
1275  c = ast_channel_unref(c);
1276  } else {
1277  ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
1278  }
1279 
1280  return CLI_SUCCESS;
1281 }
1282 
1283 /*! \brief handles CLI command 'cli show permissions' */
1284 static char *handle_cli_show_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1285 {
1286  struct usergroup_cli_perm *cp;
1287  struct cli_perm *perm;
1288  struct passwd *pw = NULL;
1289  struct group *gr = NULL;
1290 
1291  switch (cmd) {
1292  case CLI_INIT:
1293  e->command = "cli show permissions";
1294  e->usage =
1295  "Usage: cli show permissions\n"
1296  " Shows CLI configured permissions.\n";
1297  return NULL;
1298  case CLI_GENERATE:
1299  return NULL;
1300  }
1301 
1303  AST_LIST_TRAVERSE(&cli_perms, cp, list) {
1304  if (cp->uid >= 0) {
1305  pw = getpwuid(cp->uid);
1306  if (pw) {
1307  ast_cli(a->fd, "user: %s [uid=%d]\n", pw->pw_name, cp->uid);
1308  }
1309  } else {
1310  gr = getgrgid(cp->gid);
1311  if (gr) {
1312  ast_cli(a->fd, "group: %s [gid=%d]\n", gr->gr_name, cp->gid);
1313  }
1314  }
1315  ast_cli(a->fd, "Permissions:\n");
1316  if (cp->perms) {
1317  AST_LIST_TRAVERSE(cp->perms, perm, list) {
1318  ast_cli(a->fd, "\t%s -> %s\n", perm->permit ? "permit" : "deny", perm->command);
1319  }
1320  }
1321  ast_cli(a->fd, "\n");
1322  }
1324 
1325  return CLI_SUCCESS;
1326 }
1327 
1328 /*! \brief handles CLI command 'cli reload permissions' */
1329 static char *handle_cli_reload_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1330 {
1331  switch (cmd) {
1332  case CLI_INIT:
1333  e->command = "cli reload permissions";
1334  e->usage =
1335  "Usage: cli reload permissions\n"
1336  " Reload the 'cli_permissions.conf' file.\n";
1337  return NULL;
1338  case CLI_GENERATE:
1339  return NULL;
1340  }
1341 
1342  ast_cli_perms_init(1);
1343 
1344  return CLI_SUCCESS;
1345 }
1346 
1347 /*! \brief handles CLI command 'cli check permissions' */
1348 static char *handle_cli_check_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1349 {
1350  struct passwd *pw = NULL;
1351  struct group *gr;
1352  int gid = -1, uid = -1;
1353  char command[AST_MAX_ARGS] = "";
1354  struct ast_cli_entry *ce = NULL;
1355  int found = 0;
1356  char *group, *tmp;
1357 
1358  switch (cmd) {
1359  case CLI_INIT:
1360  e->command = "cli check permissions";
1361  e->usage =
1362  "Usage: cli check permissions {<username>|@<groupname>|<username>@<groupname>} [<command>]\n"
1363  " Check permissions config for a user@group or list the allowed commands for the specified user.\n"
1364  " The username or the groupname may be omitted.\n";
1365  return NULL;
1366  case CLI_GENERATE:
1367  if (a->pos >= 4) {
1368  return ast_cli_generator(a->line + strlen("cli check permissions") + strlen(a->argv[3]) + 1, a->word, a->n);
1369  }
1370  return NULL;
1371  }
1372 
1373  if (a->argc < 4) {
1374  return CLI_SHOWUSAGE;
1375  }
1376 
1377  tmp = ast_strdupa(a->argv[3]);
1378  group = strchr(tmp, '@');
1379  if (group) {
1380  gr = getgrnam(&group[1]);
1381  if (!gr) {
1382  ast_cli(a->fd, "Unknown group '%s'\n", &group[1]);
1383  return CLI_FAILURE;
1384  }
1385  group[0] = '\0';
1386  gid = gr->gr_gid;
1387  }
1388 
1389  if (!group && ast_strlen_zero(tmp)) {
1390  ast_cli(a->fd, "You didn't supply a username\n");
1391  } else if (!ast_strlen_zero(tmp) && !(pw = getpwnam(tmp))) {
1392  ast_cli(a->fd, "Unknown user '%s'\n", tmp);
1393  return CLI_FAILURE;
1394  } else if (pw) {
1395  uid = pw->pw_uid;
1396  }
1397 
1398  if (a->argc == 4) {
1399  while ((ce = cli_next(ce))) {
1400  /* Hide commands that start with '_' */
1401  if (ce->_full_cmd[0] == '_') {
1402  continue;
1403  }
1404  if (cli_has_permissions(uid, gid, ce->_full_cmd)) {
1405  ast_cli(a->fd, "%30.30s %s\n", ce->_full_cmd, S_OR(ce->summary, "<no description available>"));
1406  found++;
1407  }
1408  }
1409  if (!found) {
1410  ast_cli(a->fd, "You are not allowed to run any command on Asterisk\n");
1411  }
1412  } else {
1413  ast_join(command, sizeof(command), a->argv + 4);
1414  ast_cli(a->fd, "%s '%s%s%s' is %s to run command: '%s'\n", uid >= 0 ? "User" : "Group", tmp,
1415  group && uid >= 0 ? "@" : "",
1416  group ? &group[1] : "",
1417  cli_has_permissions(uid, gid, command) ? "allowed" : "not allowed", command);
1418  }
1419 
1420  return CLI_SUCCESS;
1421 }
1422 
1423 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
1424 
1425 static char *handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1426 {
1427  char *buf, *obuf;
1428  int buflen = 2048;
1429  int len = 0;
1430  char **matches;
1431  int x, matchlen;
1432 
1433  switch (cmd) {
1434  case CLI_INIT:
1435  e->command = "_command matchesarray";
1436  e->usage =
1437  "Usage: _command matchesarray \"<line>\" text \n"
1438  " This function is used internally to help with command completion and should.\n"
1439  " never be called by the user directly.\n";
1440  return NULL;
1441  case CLI_GENERATE:
1442  return NULL;
1443  }
1444 
1445  if (a->argc != 4)
1446  return CLI_SHOWUSAGE;
1447  if (!(buf = ast_malloc(buflen)))
1448  return CLI_FAILURE;
1449  buf[len] = '\0';
1450  matches = ast_cli_completion_matches(a->argv[2], a->argv[3]);
1451  if (matches) {
1452  for (x=0; matches[x]; x++) {
1453  matchlen = strlen(matches[x]) + 1;
1454  if (len + matchlen >= buflen) {
1455  buflen += matchlen * 3;
1456  obuf = buf;
1457  if (!(buf = ast_realloc(obuf, buflen)))
1458  /* Memory allocation failure... Just free old buffer and be done */
1459  ast_free(obuf);
1460  }
1461  if (buf)
1462  len += sprintf( buf + len, "%s ", matches[x]);
1463  ast_free(matches[x]);
1464  matches[x] = NULL;
1465  }
1466  ast_free(matches);
1467  }
1468 
1469  if (buf) {
1470  ast_cli(a->fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
1471  ast_free(buf);
1472  } else
1473  ast_cli(a->fd, "NULL\n");
1474 
1475  return CLI_SUCCESS;
1476 }
1477 
1478 
1480  int fd;
1481  int is_off;
1482 };
1483 
1484 static int channel_set_debug(void *obj, void *arg, void *data, int flags)
1485 {
1486  struct ast_channel *chan = obj;
1487  struct channel_set_debug_args *args = data;
1488 
1489  ast_channel_lock(chan);
1490 
1491  if (!(ast_channel_fin(chan) & DEBUGCHAN_FLAG) || !(ast_channel_fout(chan) & DEBUGCHAN_FLAG)) {
1492  if (args->is_off) {
1495  } else {
1498  }
1499  ast_cli(args->fd, "Debugging %s on channel %s\n", args->is_off ? "disabled" : "enabled",
1500  ast_channel_name(chan));
1501  }
1502 
1503  ast_channel_unlock(chan);
1504 
1505  return 0;
1506 }
1507 
1508 static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1509 {
1510  struct ast_channel *c = NULL;
1511  static const char * const completions_all[] = { "all", NULL };
1512  static const char * const completions_off[] = { "off", NULL };
1513  struct channel_set_debug_args args = {
1514  .fd = a->fd,
1515  };
1516 
1517  switch (cmd) {
1518  case CLI_INIT:
1519  e->command = "core set debug channel";
1520  e->usage =
1521  "Usage: core set debug channel <all|channel> [off]\n"
1522  " Enables/disables debugging on all or on a specific channel.\n";
1523  return NULL;
1524  case CLI_GENERATE:
1525  if (a->pos == 4) {
1526  char *complete = ast_cli_complete(a->word, completions_all, a->n);
1527  if (!complete) {
1528  complete = ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args);
1529  }
1530  return complete;
1531  } else if (a->pos == 5) {
1532  return ast_cli_complete(a->word, completions_off, a->n);
1533  }
1534 
1535  return NULL;
1536  }
1537 
1538  if (cmd == (CLI_HANDLER + 1000)) {
1539  /* called from handle_nodebugchan_deprecated */
1540  args.is_off = 1;
1541  } else if (a->argc == e->args + 2) {
1542  /* 'core set debug channel {all|chan_id}' */
1543  if (!strcasecmp(a->argv[e->args + 1], "off"))
1544  args.is_off = 1;
1545  else
1546  return CLI_SHOWUSAGE;
1547  } else if (a->argc != e->args + 1) {
1548  return CLI_SHOWUSAGE;
1549  }
1550 
1551  if (!strcasecmp("all", a->argv[e->args])) {
1552  if (args.is_off) {
1555  } else {
1558  }
1560  } else {
1561  if ((c = ast_channel_get_by_name(a->argv[e->args]))) {
1562  channel_set_debug(c, NULL, &args, 0);
1564  } else {
1565  ast_cli(a->fd, "No such channel %s\n", a->argv[e->args]);
1566  }
1567  }
1568 
1569  ast_cli(a->fd, "Debugging on new channels is %s\n", args.is_off ? "disabled" : "enabled");
1570 
1571  return CLI_SUCCESS;
1572 }
1573 
1574 static char *handle_debug_category(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1575 {
1576  const char *argv4 = a->argv ? S_OR(a->argv[4], "") : "";
1577  int offset = strncasecmp(argv4, "off", strlen(argv4)) ? 0 : 1;
1578 
1579  switch (cmd) {
1580  case CLI_INIT:
1581  e->command = "core set debug category";
1582  e->usage =
1583  "Usage: core set debug category <category>[:<sublevel>] [category[:<sublevel] ...]\n"
1584  " core set debug category off [<category> [<category>] ...]\n\n"
1585  " Allows enabling and disabling debug logging categories.\n"
1586  " When a category is enabled all relevant debug messages are logged\n"
1587  " for a given category. However, if a sublevel is specified only\n"
1588  " those categorized messages at or below the coded debug sublevel\n"
1589  " are logged.\n";
1590  return NULL;
1591 
1592  case CLI_GENERATE:
1593  if (a->pos < e->args) {
1594  return NULL;
1595  }
1596 
1597  if (a->pos == 4 && offset) {
1599  }
1600 
1601  return ast_debug_category_complete(a->argv + 4,
1602  a->pos - e->args, a->word, a->n - 1);
1603  }
1604 
1605  if (a->argc <= e->args) {
1606  return CLI_SHOWUSAGE;
1607  }
1608 
1609  ast_debug_category_set_sublevels(a->argv + e->args + offset, a->argc - e->args - offset,
1611 
1612  return CLI_SUCCESS;
1613 }
1614 
1615 static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1616 {
1617  char *res;
1618 
1619  switch (cmd) {
1620  case CLI_INIT:
1621  e->command = "no debug channel";
1622  return NULL;
1623  case CLI_HANDLER:
1624  /* exit out of switch statement */
1625  break;
1626  default:
1627  return NULL;
1628  }
1629 
1630  if (a->argc != e->args + 1)
1631  return CLI_SHOWUSAGE;
1632 
1633  /* add a 'magic' value to the CLI_HANDLER command so that
1634  * handle_core_set_debug_channel() will act as if 'off'
1635  * had been specified as part of the command
1636  */
1637  res = handle_core_set_debug_channel(e, CLI_HANDLER + 1000, a);
1638 
1639  return res;
1640 }
1641 
1642 static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1643 {
1644  struct ast_channel *chan;
1645  struct timeval now;
1646  char cdrtime[256];
1647  struct ast_str *obuf;/*!< Buffer for CDR variables. */
1648  struct ast_str *output;/*!< Accumulation buffer for all output. */
1649  long elapsed_seconds=0;
1650  int hour=0, min=0, sec=0;
1651  struct ast_var_t *var;
1652  struct ast_str *write_transpath = ast_str_alloca(256);
1653  struct ast_str *read_transpath = ast_str_alloca(256);
1654  struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1655  struct ast_bridge *bridge;
1657  char callid_buf[32];
1658  int stream_num;
1659 
1660  switch (cmd) {
1661  case CLI_INIT:
1662  e->command = "core show channel";
1663  e->usage =
1664  "Usage: core show channel <channel>\n"
1665  " Shows lots of information about the specified channel.\n";
1666  return NULL;
1667  case CLI_GENERATE:
1668  return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1669  }
1670 
1671  if (a->argc != 4) {
1672  return CLI_SHOWUSAGE;
1673  }
1674 
1675  obuf = ast_str_thread_get(&ast_str_thread_global_buf, 16);
1676  if (!obuf) {
1677  return CLI_FAILURE;
1678  }
1679 
1680  chan = ast_channel_get_by_name(a->argv[3]);
1681  if (!chan) {
1682  ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
1683 
1684  return CLI_SUCCESS;
1685  }
1686 
1687  output = ast_str_create(8192);
1688  if (!output) {
1689  ast_channel_unref(chan);
1690 
1691  return CLI_FAILURE;
1692  }
1693 
1694  now = ast_tvnow();
1695  ast_channel_lock(chan);
1696 
1697  if (!ast_tvzero(ast_channel_creationtime(chan))) {
1698  elapsed_seconds = now.tv_sec - ast_channel_creationtime(chan).tv_sec;
1699  hour = elapsed_seconds / 3600;
1700  min = (elapsed_seconds % 3600) / 60;
1701  sec = elapsed_seconds % 60;
1702  snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
1703  } else {
1704  strcpy(cdrtime, "N/A");
1705  }
1706 
1707  ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath);
1708  ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath);
1709 
1710  bridge = ast_channel_get_bridge(chan);
1711  callid_buf[0] = '\0';
1712  callid = ast_channel_callid(chan);
1713  if (callid) {
1714  ast_callid_strnprint(callid_buf, sizeof(callid_buf), callid);
1715  }
1716 
1717  ast_str_append(&output, 0,
1718  " -- General --\n"
1719  " Name: %s\n"
1720  " Type: %s\n"
1721  " UniqueID: %s\n"
1722  " LinkedID: %s\n"
1723  " Caller ID: %s\n"
1724  " Caller ID Name: %s\n"
1725  "Connected Line ID: %s\n"
1726  "Connected Line ID Name: %s\n"
1727  "Eff. Connected Line ID: %s\n"
1728  "Eff. Connected Line ID Name: %s\n"
1729  " DNID Digits: %s\n"
1730  " Language: %s\n"
1731  " State: %s (%u)\n"
1732  " NativeFormats: %s\n"
1733  " WriteFormat: %s\n"
1734  " ReadFormat: %s\n"
1735  " WriteTranscode: %s %s\n"
1736  " ReadTranscode: %s %s\n"
1737  " Time to Hangup: %ld\n"
1738  " Elapsed Time: %s\n"
1739  " Bridge ID: %s\n"
1740  " -- PBX --\n"
1741  " Context: %s\n"
1742  " Extension: %s\n"
1743  " Priority: %d\n"
1744  " Call Group: %llu\n"
1745  " Pickup Group: %llu\n"
1746  " Application: %s\n"
1747  " Data: %s\n"
1748  " Call Identifer: %s\n",
1749  ast_channel_name(chan),
1750  ast_channel_tech(chan)->type,
1751  ast_channel_uniqueid(chan),
1752  ast_channel_linkedid(chan),
1753  S_COR(ast_channel_caller(chan)->id.number.valid,
1754  ast_channel_caller(chan)->id.number.str, "(N/A)"),
1755  S_COR(ast_channel_caller(chan)->id.name.valid,
1756  ast_channel_caller(chan)->id.name.str, "(N/A)"),
1757  S_COR(ast_channel_connected(chan)->id.number.valid,
1758  ast_channel_connected(chan)->id.number.str, "(N/A)"),
1759  S_COR(ast_channel_connected(chan)->id.name.valid,
1760  ast_channel_connected(chan)->id.name.str, "(N/A)"),
1762  ast_channel_connected_effective_id(chan).number.str, "(N/A)"),
1764  ast_channel_connected_effective_id(chan).name.str, "(N/A)"),
1765  S_OR(ast_channel_dialed(chan)->number.str, "(N/A)"),
1766  ast_channel_language(chan),
1768  ast_channel_state(chan),
1772  ast_str_strlen(write_transpath) ? "Yes" : "No",
1773  ast_str_buffer(write_transpath),
1774  ast_str_strlen(read_transpath) ? "Yes" : "No",
1775  ast_str_buffer(read_transpath),
1776  (long)ast_channel_whentohangup(chan)->tv_sec,
1777  cdrtime,
1778  bridge ? bridge->uniqueid : "(Not bridged)",
1779  ast_channel_context(chan),
1780  ast_channel_exten(chan),
1781  ast_channel_priority(chan),
1782  ast_channel_callgroup(chan),
1784  S_OR(ast_channel_appl(chan), "(N/A)"),
1785  S_OR(ast_channel_data(chan), "(Empty)"),
1786  S_OR(callid_buf, "(None)")
1787  );
1788 
1789  ast_str_append(&output, 0, " Variables:\n");
1790 
1791  AST_LIST_TRAVERSE(ast_channel_varshead(chan), var, entries) {
1792  ast_str_append(&output, 0, "%s=%s\n", ast_var_name(var), ast_var_value(var));
1793  }
1794 
1795  if (!(ast_channel_tech(chan)->properties & AST_CHAN_TP_INTERNAL)
1796  && ast_cdr_serialize_variables(ast_channel_name(chan), &obuf, '=', '\n')) {
1797  ast_str_append(&output, 0, " CDR Variables:\n%s\n", ast_str_buffer(obuf));
1798  }
1799 
1800  ast_str_append(&output, 0, " -- Streams --\n");
1801  for (stream_num = 0; stream_num < ast_stream_topology_get_count(ast_channel_get_stream_topology(chan)); stream_num++) {
1803  struct ast_variable *metadata = ast_stream_get_metadata_list(stream);
1804 
1805  ast_str_append(&output, 0,
1806  "Name: %s\n"
1807  " Type: %s\n"
1808  " State: %s\n"
1809  " Group: %d\n"
1810  " Formats: %s\n"
1811  " Metadata:\n",
1812  ast_stream_get_name(stream),
1815  ast_stream_get_group(stream),
1817  );
1818 
1819  if (metadata) {
1820  struct ast_variable *v;
1821  for(v = metadata; v; v = v->next) {
1822  ast_str_append(&output, 0, " %s: %s\n", v->name, v->value);
1823  }
1824  ast_variables_destroy(metadata);
1825  }
1826  }
1827 
1828  ast_channel_unlock(chan);
1829 
1830  ast_cli(a->fd, "%s", ast_str_buffer(output));
1831  ast_free(output);
1832 
1833  ao2_cleanup(bridge);
1834  ast_channel_unref(chan);
1835 
1836  return CLI_SUCCESS;
1837 }
1838 
1839 /*
1840  * helper function to generate CLI matches from a fixed set of values.
1841  * A NULL word is acceptable.
1842  */
1843 char *ast_cli_complete(const char *word, const char * const choices[], int state)
1844 {
1845  int i, which = 0, len;
1846  len = ast_strlen_zero(word) ? 0 : strlen(word);
1847 
1848  for (i = 0; choices[i]; i++) {
1849  if ((!len || !strncasecmp(word, choices[i], len)) && ++which > state) {
1850  if (state != -1) {
1851  return ast_strdup(choices[i]);
1852  }
1853 
1854  if (ast_cli_completion_add(ast_strdup(choices[i]))) {
1855  return NULL;
1856  }
1857  }
1858  }
1859  return NULL;
1860 }
1861 
1862 char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
1863 {
1864  int wordlen = strlen(word), which = 0;
1865  struct ao2_container *cached_channels;
1866  char *ret = NULL;
1867  struct ao2_iterator iter;
1868  struct ast_channel_snapshot *snapshot;
1869 
1870  if (pos != rpos) {
1871  return NULL;
1872  }
1873 
1874  cached_channels = ast_channel_cache_all();
1875 
1876  iter = ao2_iterator_init(cached_channels, 0);
1877  for (; (snapshot = ao2_iterator_next(&iter)); ao2_ref(snapshot, -1)) {
1878  if (!strncasecmp(word, snapshot->base->name, wordlen) && (++which > state)) {
1879  if (state != -1) {
1880  ret = ast_strdup(snapshot->base->name);
1881  ao2_ref(snapshot, -1);
1882  break;
1883  }
1884 
1885  if (ast_cli_completion_add(ast_strdup(snapshot->base->name))) {
1886  ao2_ref(snapshot, -1);
1887  break;
1888  }
1889  }
1890  }
1891  ao2_iterator_destroy(&iter);
1892  ao2_ref(cached_channels, -1);
1893 
1894  return ret;
1895 }
1896 
1897 static char *group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1898 {
1899 #define FORMAT_STRING "%-25s %-20s %-20s\n"
1900 
1901  struct ast_group_info *gi = NULL;
1902  int numchans = 0;
1903  regex_t regexbuf;
1904  int havepattern = 0;
1905 
1906  switch (cmd) {
1907  case CLI_INIT:
1908  e->command = "group show channels";
1909  e->usage =
1910  "Usage: group show channels [pattern]\n"
1911  " Lists all currently active channels with channel group(s) specified.\n"
1912  " Optional regular expression pattern is matched to group names for each\n"
1913  " channel.\n";
1914  return NULL;
1915  case CLI_GENERATE:
1916  return NULL;
1917  }
1918 
1919  if (a->argc < 3 || a->argc > 4)
1920  return CLI_SHOWUSAGE;
1921 
1922  if (a->argc == 4) {
1923  if (regcomp(&regexbuf, a->argv[3], REG_EXTENDED | REG_NOSUB))
1924  return CLI_SHOWUSAGE;
1925  havepattern = 1;
1926  }
1927 
1928  ast_cli(a->fd, FORMAT_STRING, "Channel", "Group", "Category");
1929 
1931 
1932  gi = ast_app_group_list_head();
1933  while (gi) {
1934  if (!havepattern || !regexec(&regexbuf, gi->group, 0, NULL, 0)) {
1935  ast_cli(a->fd, FORMAT_STRING, ast_channel_name(gi->chan), gi->group, (ast_strlen_zero(gi->category) ? "(default)" : gi->category));
1936  numchans++;
1937  }
1938  gi = AST_LIST_NEXT(gi, group_list);
1939  }
1940 
1942 
1943  if (havepattern)
1944  regfree(&regexbuf);
1945 
1946  ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
1947  return CLI_SUCCESS;
1948 #undef FORMAT_STRING
1949 }
1950 
1951 static char *handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1952 {
1953  switch (cmd) {
1954  case CLI_INIT:
1955  e->command = "core waitfullybooted";
1956  e->usage =
1957  "Usage: core waitfullybooted\n"
1958  " Wait until Asterisk has fully booted.\n";
1959  return NULL;
1960  case CLI_GENERATE:
1961  return NULL;
1962  }
1963 
1965  usleep(100);
1966  }
1967 
1968  ast_cli(a->fd, "Asterisk has fully booted.\n");
1969 
1970  return CLI_SUCCESS;
1971 }
1972 
1973 
1974 #ifdef HAVE_MALLOC_TRIM
1975 
1976 /*!
1977  * \internal
1978  * \brief Attempt to reclaim unused heap memory.
1979  *
1980  * Users have reported that asterisk will sometimes be killed because it can't allocate
1981  * more than around 3G of memory on a 32 bit system.
1982  *
1983  * Using malloc_trim() will help us to determine if it's because there's a leak or because
1984  * the heap is so fragmented that there isn't enough contiguous memory available.
1985  *
1986  * \note malloc_trim() is a GNU extension and is therefore not portable.
1987  */
1988 static char *handle_cli_malloc_trim(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1989 {
1990  extern int malloc_trim(size_t __pad) __THROW;
1991 
1992  switch (cmd) {
1993  case CLI_INIT:
1994  e->command = "malloc trim";
1995  e->usage =
1996  "Usage: malloc trim\n"
1997  " Try to give excess memory back to the OS.\n";
1998  return NULL;
1999  case CLI_GENERATE:
2000  return NULL;
2001  }
2002 
2003  if (malloc_trim(0)) {
2004  ast_cli(a->fd, "Returned some memory to the OS.\n");
2005  } else {
2006  ast_cli(a->fd, "No memory returned to the OS.\n");
2007  }
2008 
2009  return CLI_SUCCESS;
2010 }
2011 
2012 #endif
2013 
2014 static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
2015 
2016 static struct ast_cli_entry cli_cli[] = {
2017  AST_CLI_DEFINE(handle_commandmatchesarray, "Returns command matches array"),
2018 
2019  AST_CLI_DEFINE(handle_nodebugchan_deprecated, "Disable debugging on channel(s)"),
2020 
2021  AST_CLI_DEFINE(handle_chanlist, "Display information on channels"),
2022 
2023  AST_CLI_DEFINE(handle_showcalls, "Display information on calls"),
2024 
2025  AST_CLI_DEFINE(handle_showchan, "Display information on a specific channel"),
2026 
2027  AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
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(group_show_channels, "Display active channels with group(s)"),
2036 
2037  AST_CLI_DEFINE(handle_help, "Display help list, or specific help on a command"),
2038 
2039  AST_CLI_DEFINE(handle_logger_mute, "Toggle logging output to a console"),
2040 
2041  AST_CLI_DEFINE(handle_modlist, "List modules and info"),
2042 
2043  AST_CLI_DEFINE(handle_load, "Load a module by name"),
2044 
2045  AST_CLI_DEFINE(handle_reload, "Reload configuration for a module"),
2046 
2047  AST_CLI_DEFINE(handle_core_reload, "Global reload"),
2048 
2049  AST_CLI_DEFINE(handle_unload, "Unload a module by name"),
2050 
2051  AST_CLI_DEFINE(handle_refresh, "Completely unloads and loads a module by name"),
2052 
2053  AST_CLI_DEFINE(handle_showuptime, "Show uptime information"),
2054 
2055  AST_CLI_DEFINE(handle_softhangup, "Request a hangup on a given channel"),
2056 
2057  AST_CLI_DEFINE(handle_cli_reload_permissions, "Reload CLI permissions config"),
2058 
2059  AST_CLI_DEFINE(handle_cli_show_permissions, "Show CLI permissions"),
2060 
2061  AST_CLI_DEFINE(handle_cli_check_permissions, "Try a permissions config for a user"),
2062 
2063  AST_CLI_DEFINE(handle_cli_wait_fullybooted, "Wait for Asterisk to be fully booted"),
2064 
2065 #ifdef HAVE_MALLOC_TRIM
2066  AST_CLI_DEFINE(handle_cli_malloc_trim, "Return excess memory to the OS"),
2067 #endif
2068 
2069 };
2070 
2071 /*!
2072  * Some regexp characters in cli arguments are reserved and used as separators.
2073  */
2074 static const char cli_rsvd[] = "[]{}|*%";
2075 
2076 /*!
2077  * initialize the _full_cmd string and related parameters,
2078  * return 0 on success, -1 on error.
2079  */
2080 static int set_full_cmd(struct ast_cli_entry *e)
2081 {
2082  int i;
2083  char buf[80];
2084 
2085  ast_join(buf, sizeof(buf), e->cmda);
2086  e->_full_cmd = ast_strdup(buf);
2087  if (!e->_full_cmd) {
2088  ast_log(LOG_WARNING, "-- cannot allocate <%s>\n", buf);
2089  return -1;
2090  }
2091  e->cmdlen = strcspn(e->_full_cmd, cli_rsvd);
2092  for (i = 0; e->cmda[i]; i++)
2093  ;
2094  e->args = i;
2095  return 0;
2096 }
2097 
2098 /*! \brief cleanup (free) cli_perms linkedlist. */
2099 static void destroy_user_perms(void)
2100 {
2101  struct cli_perm *perm;
2102  struct usergroup_cli_perm *user_perm;
2103 
2105  while ((user_perm = AST_LIST_REMOVE_HEAD(&cli_perms, list))) {
2106  while ((perm = AST_LIST_REMOVE_HEAD(user_perm->perms, list))) {
2107  ast_free(perm->command);
2108  ast_free(perm);
2109  }
2110  ast_free(user_perm);
2111  }
2113 }
2114 
2116 {
2117  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
2118  struct ast_config *cfg;
2119  char *cat = NULL;
2120  struct ast_variable *v;
2121  struct usergroup_cli_perm *user_group, *cp_entry;
2122  struct cli_perm *perm = NULL;
2123  struct passwd *pw;
2124  struct group *gr;
2125 
2127  ast_log(LOG_NOTICE, "You must wait until last 'cli reload permissions' command finish\n");
2128  return 1;
2129  }
2130 
2131  cfg = ast_config_load2(perms_config, "" /* core, can't reload */, config_flags);
2132  if (!cfg) {
2134  return 1;
2135  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
2137  return 0;
2138  }
2139 
2140  /* free current structures. */
2142 
2143  while ((cat = ast_category_browse(cfg, cat))) {
2144  if (!strcasecmp(cat, "general")) {
2145  /* General options */
2146  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
2147  if (!strcasecmp(v->name, "default_perm")) {
2148  cli_default_perm = (!strcasecmp(v->value, "permit")) ? 1: 0;
2149  }
2150  }
2151  continue;
2152  }
2153 
2154  /* users or groups */
2155  gr = NULL, pw = NULL;
2156  if (cat[0] == '@') {
2157  /* This is a group */
2158  gr = getgrnam(&cat[1]);
2159  if (!gr) {
2160  ast_log (LOG_WARNING, "Unknown group '%s'\n", &cat[1]);
2161  continue;
2162  }
2163  } else {
2164  /* This is a user */
2165  pw = getpwnam(cat);
2166  if (!pw) {
2167  ast_log (LOG_WARNING, "Unknown user '%s'\n", cat);
2168  continue;
2169  }
2170  }
2171  user_group = NULL;
2172  /* Check for duplicates */
2174  AST_LIST_TRAVERSE(&cli_perms, cp_entry, list) {
2175  if ((pw && cp_entry->uid == pw->pw_uid) || (gr && cp_entry->gid == gr->gr_gid)) {
2176  /* if it is duplicated, just added this new settings, to
2177  the current list. */
2178  user_group = cp_entry;
2179  break;
2180  }
2181  }
2183 
2184  if (!user_group) {
2185  /* alloc space for the new user config. */
2186  user_group = ast_calloc(1, sizeof(*user_group));
2187  if (!user_group) {
2188  continue;
2189  }
2190  user_group->uid = (pw ? pw->pw_uid : -1);
2191  user_group->gid = (gr ? gr->gr_gid : -1);
2192  user_group->perms = ast_calloc(1, sizeof(*user_group->perms));
2193  if (!user_group->perms) {
2194  ast_free(user_group);
2195  continue;
2196  }
2197  }
2198  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
2199  if (ast_strlen_zero(v->value)) {
2200  /* we need to check this condition cause it could break security. */
2201  ast_log(LOG_WARNING, "Empty permit/deny option in user '%s'\n", cat);
2202  continue;
2203  }
2204  if (!strcasecmp(v->name, "permit")) {
2205  perm = ast_calloc(1, sizeof(*perm));
2206  if (perm) {
2207  perm->permit = 1;
2208  perm->command = ast_strdup(v->value);
2209  }
2210  } else if (!strcasecmp(v->name, "deny")) {
2211  perm = ast_calloc(1, sizeof(*perm));
2212  if (perm) {
2213  perm->permit = 0;
2214  perm->command = ast_strdup(v->value);
2215  }
2216  } else {
2217  /* up to now, only 'permit' and 'deny' are possible values. */
2218  ast_log(LOG_WARNING, "Unknown '%s' option\n", v->name);
2219  continue;
2220  }
2221  if (perm) {
2222  /* Added the permission to the user's list. */
2223  AST_LIST_INSERT_TAIL(user_group->perms, perm, list);
2224  perm = NULL;
2225  }
2226  }
2228  AST_RWLIST_INSERT_TAIL(&cli_perms, user_group, list);
2230  }
2231 
2232  ast_config_destroy(cfg);
2234  return 0;
2235 }
2236 
2237 static void cli_shutdown(void)
2238 {
2240 }
2241 
2242 /*! \brief initialize the _full_cmd string in * each of the builtins. */
2244 {
2248 }
2249 
2250 /*!
2251  * match a word in the CLI entry.
2252  * returns -1 on mismatch, 0 on match of an optional word,
2253  * 1 on match of a full word.
2254  *
2255  * The pattern can be
2256  * any_word match for equal
2257  * [foo|bar|baz] optionally, one of these words
2258  * {foo|bar|baz} exactly, one of these words
2259  * % any word
2260  */
2261 static int word_match(const char *cmd, const char *cli_word)
2262 {
2263  int l;
2264  char *pos;
2265 
2266  if (ast_strlen_zero(cmd) || ast_strlen_zero(cli_word))
2267  return -1;
2268  if (!strchr(cli_rsvd, cli_word[0])) /* normal match */
2269  return (strcasecmp(cmd, cli_word) == 0) ? 1 : -1;
2270  l = strlen(cmd);
2271  /* wildcard match - will extend in the future */
2272  if (l > 0 && cli_word[0] == '%') {
2273  return 1; /* wildcard */
2274  }
2275 
2276  /* Start a search for the command entered against the cli word in question */
2277  pos = strcasestr(cli_word, cmd);
2278  while (pos) {
2279 
2280  /*
2281  *Check if the word matched with is surrounded by reserved characters on both sides
2282  * and isn't at the beginning of the cli_word since that would make it check in a location we shouldn't know about.
2283  * If it is surrounded by reserved chars and isn't at the beginning, it's a match.
2284  */
2285  if (pos != cli_word && strchr(cli_rsvd, pos[-1]) && strchr(cli_rsvd, pos[l])) {
2286  return 1; /* valid match */
2287  }
2288 
2289  /* Ok, that one didn't match, strcasestr to the next appearance of the command and start over.*/
2290  pos = strcasestr(pos + 1, cmd);
2291  }
2292  /* If no matches were found over the course of the while loop, we hit the end of the string. It's a mismatch. */
2293  return -1;
2294 }
2295 
2296 /*! \brief if word is a valid prefix for token, returns the pos-th
2297  * match as a malloced string, or NULL otherwise.
2298  * Always tell in *actual how many matches we got.
2299  */
2300 static char *is_prefix(const char *word, const char *token,
2301  int pos, int *actual)
2302 {
2303  int lw;
2304  char *s, *t1;
2305 
2306  *actual = 0;
2307  if (ast_strlen_zero(token))
2308  return NULL;
2309  if (ast_strlen_zero(word))
2310  word = ""; /* dummy */
2311  lw = strlen(word);
2312  if (strcspn(word, cli_rsvd) != lw)
2313  return NULL; /* no match if word has reserved chars */
2314  if (strchr(cli_rsvd, token[0]) == NULL) { /* regular match */
2315  if (strncasecmp(token, word, lw)) /* no match */
2316  return NULL;
2317  *actual = 1;
2318  return (pos != 0) ? NULL : ast_strdup(token);
2319  }
2320  /* now handle regexp match */
2321 
2322  /* Wildcard always matches, so we never do is_prefix on them */
2323 
2324  t1 = ast_strdupa(token + 1); /* copy, skipping first char */
2325  while (pos >= 0 && (s = strsep(&t1, cli_rsvd)) && *s) {
2326  if (*s == '%') /* wildcard */
2327  continue;
2328  if (strncasecmp(s, word, lw)) /* no match */
2329  continue;
2330  (*actual)++;
2331  if (pos-- == 0)
2332  return ast_strdup(s);
2333  }
2334  return NULL;
2335 }
2336 
2337 /*!
2338  * \internal
2339  * \brief locate a cli command in the 'helpers' list (which must be locked).
2340  * The search compares word by word taking care of regexps in e->cmda
2341  * This function will return NULL when nothing is matched, or the ast_cli_entry that matched.
2342  * \param cmds
2343  * \param match_type has 3 possible values:
2344  * 0 returns if the search key is equal or longer than the entry.
2345  * note that trailing optional arguments are skipped.
2346  * -1 true if the mismatch is on the last word XXX not true!
2347  * 1 true only on complete, exact match.
2348  *
2349  */
2350 static struct ast_cli_entry *find_cli(const char * const cmds[], int match_type)
2351 {
2352  int matchlen = -1; /* length of longest match so far */
2353  struct ast_cli_entry *cand = NULL, *e=NULL;
2354 
2355  while ( (e = cli_next(e)) ) {
2356  /* word-by word regexp comparison */
2357  const char * const *src = cmds;
2358  const char * const *dst = e->cmda;
2359  int n = 0;
2360  for (;; dst++, src += n) {
2361  n = word_match(*src, *dst);
2362  if (n < 0)
2363  break;
2364  }
2365  if (ast_strlen_zero(*dst) || ((*dst)[0] == '[' && ast_strlen_zero(dst[1]))) {
2366  /* no more words in 'e' */
2367  if (ast_strlen_zero(*src)) /* exact match, cannot do better */
2368  break;
2369  /* Here, cmds has more words than the entry 'e' */
2370  if (match_type != 0) /* but we look for almost exact match... */
2371  continue; /* so we skip this one. */
2372  /* otherwise we like it (case 0) */
2373  } else { /* still words in 'e' */
2374  if (ast_strlen_zero(*src))
2375  continue; /* cmds is shorter than 'e', not good */
2376  /* Here we have leftover words in cmds and 'e',
2377  * but there is a mismatch. We only accept this one if match_type == -1
2378  * and this is the last word for both.
2379  */
2380  if (match_type != -1 || !ast_strlen_zero(src[1]) ||
2381  !ast_strlen_zero(dst[1])) /* not the one we look for */
2382  continue;
2383  /* good, we are in case match_type == -1 and mismatch on last word */
2384  }
2385  if (src - cmds > matchlen) { /* remember the candidate */
2386  matchlen = src - cmds;
2387  cand = e;
2388  }
2389  }
2390 
2391  return e ? e : cand;
2392 }
2393 
2394 static char *find_best(const char *argv[])
2395 {
2396  static char cmdline[80];
2397  int x;
2398  /* See how close we get, then print the candidate */
2399  const char *myargv[AST_MAX_CMD_LEN] = { NULL, };
2400 
2402  for (x = 0; argv[x]; x++) {
2403  myargv[x] = argv[x];
2404  if (!find_cli(myargv, -1))
2405  break;
2406  }
2408  ast_join(cmdline, sizeof(cmdline), myargv);
2409  return cmdline;
2410 }
2411 
2412 static int cli_is_registered(struct ast_cli_entry *e)
2413 {
2414  struct ast_cli_entry *cur = NULL;
2415 
2416  while ((cur = cli_next(cur))) {
2417  if (cur == e) {
2418  return 1;
2419  }
2420  }
2421  return 0;
2422 }
2423 
2425 {
2429 }
2430 
2432 {
2433  if (e->inuse) {
2434  ast_log(LOG_WARNING, "Can't remove command that is in use\n");
2435  } else {
2440  ast_free(e->_full_cmd);
2441  e->_full_cmd = NULL;
2442  if (e->handler) {
2443  /* this is a new-style entry. Reset fields and free memory. */
2444  char *cmda = (char *) e->cmda;
2445  memset(cmda, '\0', sizeof(e->cmda));
2446  ast_free(e->command);
2447  e->command = NULL;
2448  e->usage = NULL;
2449  }
2450  }
2451  return 0;
2452 }
2453 
2455 {
2456  struct ast_cli_entry *cur;
2457  int i, lf, ret = -1;
2458 
2459  struct ast_cli_args a; /* fake argument */
2460  char **dst = (char **)e->cmda; /* need to cast as the entry is readonly */
2461  char *s;
2462 
2464 
2465  if (cli_is_registered(e)) {
2466  ast_log(LOG_WARNING, "Command '%s' already registered (the same ast_cli_entry)\n",
2467  S_OR(e->_full_cmd, e->command));
2468  ret = 0; /* report success */
2469  goto done;
2470  }
2471 
2472  memset(&a, '\0', sizeof(a));
2473 
2474  e->module = module;
2475  /* No module reference needed here, the module called us. */
2476  e->handler(e, CLI_INIT, &a);
2477 
2478  /* XXX check that usage and command are filled up */
2479  s = ast_skip_blanks(e->command);
2480  s = e->command = ast_strdup(s);
2481  for (i=0; !ast_strlen_zero(s) && i < AST_MAX_CMD_LEN-1; i++) {
2482  *dst++ = s; /* store string */
2483  s = ast_skip_nonblanks(s);
2484  if (*s == '\0') /* we are done */
2485  break;
2486  *s++ = '\0';
2487  s = ast_skip_blanks(s);
2488  }
2489  *dst++ = NULL;
2490 
2491  if (find_cli(e->cmda, 1)) {
2492  ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n",
2493  S_OR(e->_full_cmd, e->command));
2494  goto done;
2495  }
2496  if (set_full_cmd(e)) {
2497  ast_log(LOG_WARNING, "Error registering CLI Command '%s'\n",
2498  S_OR(e->_full_cmd, e->command));
2499  goto done;
2500  }
2501 
2502  lf = e->cmdlen;
2504  int len = cur->cmdlen;
2505  if (lf < len)
2506  len = lf;
2507  if (strncasecmp(e->_full_cmd, cur->_full_cmd, len) < 0) {
2509  break;
2510  }
2511  }
2513 
2514  if (!cur)
2515  AST_RWLIST_INSERT_TAIL(&helpers, e, list);
2516  ret = 0; /* success */
2517 
2518 done:
2520  if (ret) {
2521  ast_free(e->command);
2522  e->command = NULL;
2523  }
2524 
2525  return ret;
2526 }
2527 
2528 /*
2529  * register/unregister an array of entries.
2530  */
2531 int __ast_cli_register_multiple(struct ast_cli_entry *e, int len, struct ast_module *module)
2532 {
2533  int i, res = 0;
2534 
2535  for (i = 0; i < len; i++) {
2536  res |= __ast_cli_register(e + i, module);
2537  }
2538 
2539  return res;
2540 }
2541 
2543 {
2544  int i, res = 0;
2545 
2546  for (i = 0; i < len; i++)
2547  res |= ast_cli_unregister(e + i);
2548 
2549  return res;
2550 }
2551 
2552 
2553 /*! \brief helper for final part of handle_help
2554  * if locked = 1, assume the list is already locked
2555  */
2556 static char *help1(int fd, const char * const match[], int locked)
2557 {
2558  char matchstr[80] = "";
2559  struct ast_cli_entry *e = NULL;
2560  int len = 0;
2561  int found = 0;
2562 
2563  if (match) {
2564  ast_join(matchstr, sizeof(matchstr), match);
2565  len = strlen(matchstr);
2566  }
2567  if (!locked)
2569  while ( (e = cli_next(e)) ) {
2570  /* Hide commands that start with '_' */
2571  if (e->_full_cmd[0] == '_')
2572  continue;
2573  if (match && strncasecmp(matchstr, e->_full_cmd, len))
2574  continue;
2575  ast_cli(fd, "%-30s -- %s\n", e->_full_cmd,
2576  S_OR(e->summary, "<no description available>"));
2577  found++;
2578  }
2579  if (!locked)
2581  if (!found && matchstr[0])
2582  ast_cli(fd, "No such command '%s'.\n", matchstr);
2583  return CLI_SUCCESS;
2584 }
2585 
2586 static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2587 {
2588  char fullcmd[80];
2589  struct ast_cli_entry *my_e;
2590  char *res = CLI_SUCCESS;
2591 
2592  if (cmd == CLI_INIT) {
2593  e->command = "core show help";
2594  e->usage =
2595  "Usage: core show help [topic]\n"
2596  " When called with a topic as an argument, displays usage\n"
2597  " information on the given command. If called without a\n"
2598  " topic, it provides a list of commands.\n";
2599  return NULL;
2600 
2601  } else if (cmd == CLI_GENERATE) {
2602  /* skip first 14 or 15 chars, "core show help " */
2603  int l = strlen(a->line);
2604 
2605  if (l > 15) {
2606  l = 15;
2607  }
2608  /* XXX watch out, should stop to the non-generator parts */
2609  return __ast_cli_generator(a->line + l, a->word, a->n, 0);
2610  }
2611  if (a->argc == e->args) {
2612  return help1(a->fd, NULL, 0);
2613  }
2614 
2616  my_e = find_cli(a->argv + 3, 1); /* try exact match first */
2617  if (!my_e) {
2618  res = help1(a->fd, a->argv + 3, 1 /* locked */);
2620  return res;
2621  }
2622  if (my_e->usage)
2623  ast_cli(a->fd, "%s", my_e->usage);
2624  else {
2625  ast_join(fullcmd, sizeof(fullcmd), a->argv + 3);
2626  ast_cli(a->fd, "No help text available for '%s'.\n", fullcmd);
2627  }
2629  return res;
2630 }
2631 
2632 static char *parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
2633 {
2634  char *duplicate, *cur;
2635  int x = 0;
2636  int quoted = 0;
2637  int escaped = 0;
2638  int whitespace = 1;
2639  int dummy = 0;
2640 
2641  if (trailingwhitespace == NULL)
2642  trailingwhitespace = &dummy;
2643  *trailingwhitespace = 0;
2644  if (s == NULL) /* invalid, though! */
2645  return NULL;
2646  /* make a copy to store the parsed string */
2647  if (!(duplicate = ast_strdup(s)))
2648  return NULL;
2649 
2650  cur = duplicate;
2651 
2652  /* Remove leading spaces from the command */
2653  while (isspace(*s)) {
2654  cur++;
2655  s++;
2656  }
2657 
2658  /* scan the original string copying into cur when needed */
2659  for (; *s ; s++) {
2660  if (x >= max - 1) {
2661  ast_log(LOG_WARNING, "Too many arguments, truncating at %s\n", s);
2662  break;
2663  }
2664  if (*s == '"' && !escaped) {
2665  quoted = !quoted;
2666  if (quoted && whitespace) {
2667  /* start a quoted string from previous whitespace: new argument */
2668  argv[x++] = cur;
2669  whitespace = 0;
2670  }
2671  } else if ((*s == ' ' || *s == '\t') && !(quoted || escaped)) {
2672  /* If we are not already in whitespace, and not in a quoted string or
2673  processing an escape sequence, and just entered whitespace, then
2674  finalize the previous argument and remember that we are in whitespace
2675  */
2676  if (!whitespace) {
2677  *cur++ = '\0';
2678  whitespace = 1;
2679  }
2680  } else if (*s == '\\' && !escaped) {
2681  escaped = 1;
2682  } else {
2683  if (whitespace) {
2684  /* we leave whitespace, and are not quoted. So it's a new argument */
2685  argv[x++] = cur;
2686  whitespace = 0;
2687  }
2688  *cur++ = *s;
2689  escaped = 0;
2690  }
2691  }
2692  /* Null terminate */
2693  *cur++ = '\0';
2694  /* XXX put a NULL in the last argument, because some functions that take
2695  * the array may want a null-terminated array.
2696  * argc still reflects the number of non-NULL entries.
2697  */
2698  argv[x] = NULL;
2699  *argc = x;
2700  *trailingwhitespace = whitespace;
2701  return duplicate;
2702 }
2703 
2704 char **ast_cli_completion_matches(const char *text, const char *word)
2705 {
2707  char **match_list;
2708 
2709  if (!vec) {
2710  return NULL;
2711  }
2712 
2713  if (AST_VECTOR_APPEND(vec, NULL)) {
2714  /* We failed to NULL terminate the elements */
2716  AST_VECTOR_PTR_FREE(vec);
2717 
2718  return NULL;
2719  }
2720 
2721  match_list = AST_VECTOR_STEAL_ELEMENTS(vec);
2722  AST_VECTOR_PTR_FREE(vec);
2723 
2724  return match_list;
2725 }
2726 
2727 AST_THREADSTORAGE_RAW(completion_storage);
2728 
2729 /*!
2730  * \internal
2731  * \brief Add a value to the vector.
2732  *
2733  * \param vec Vector to add \a value to. Must be from threadstorage.
2734  * \param value The value to add.
2735  *
2736  * \retval 0 Success
2737  * \retval -1 Failure
2738  */
2739 static int cli_completion_vector_add(struct ast_vector_string *vec, char *value)
2740 {
2741  if (!value) {
2742  return 0;
2743  }
2744 
2745  if (!vec || AST_VECTOR_ADD_SORTED(vec, value, strcasecmp)) {
2746  if (vec) {
2747  ast_threadstorage_set_ptr(&completion_storage, NULL);
2748 
2750  AST_VECTOR_FREE(vec);
2751  }
2752  ast_free(value);
2753 
2754  return -1;
2755  }
2756 
2757  return 0;
2758 }
2759 
2761 {
2762  return cli_completion_vector_add(ast_threadstorage_get_ptr(&completion_storage), value);
2763 }
2764 
2765 struct ast_vector_string *ast_cli_completion_vector(const char *text, const char *word)
2766 {
2767  char *retstr, *prevstr;
2768  size_t max_equal;
2769  size_t which = 0;
2770  struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec));
2771 
2772  /* Recursion into this function is a coding error. */
2773  ast_assert(!ast_threadstorage_get_ptr(&completion_storage));
2774 
2775  if (!vec) {
2776  return NULL;
2777  }
2778 
2779  if (ast_threadstorage_set_ptr(&completion_storage, vec)) {
2780  ast_log(LOG_ERROR, "Failed to initialize threadstorage for completion.\n");
2781  ast_free(vec);
2782 
2783  return NULL;
2784  }
2785 
2786  while ((retstr = ast_cli_generator(text, word, which)) != NULL) {
2787  if (cli_completion_vector_add(vec, retstr)) {
2788  ast_threadstorage_set_ptr(&completion_storage, NULL);
2789 
2790  goto vector_cleanup;
2791  }
2792 
2793  ++which;
2794  }
2795 
2796  ast_threadstorage_set_ptr(&completion_storage, NULL);
2797 
2798  if (!AST_VECTOR_SIZE(vec)) {
2799  AST_VECTOR_PTR_FREE(vec);
2800 
2801  return NULL;
2802  }
2803 
2804  prevstr = AST_VECTOR_GET(vec, 0);
2805  max_equal = strlen(prevstr);
2806  which = 1;
2807 
2808  /* Find the longest substring that is common to all results
2809  * (it is a candidate for completion), and store a copy in entry 0.
2810  */
2811  while (which < AST_VECTOR_SIZE(vec)) {
2812  size_t i = 0;
2813 
2814  retstr = AST_VECTOR_GET(vec, which);
2815  /* Check for and remove duplicate strings. */
2816  if (!strcasecmp(prevstr, retstr)) {
2817  AST_VECTOR_REMOVE(vec, which, 1);
2818  ast_free(retstr);
2819 
2820  continue;
2821  }
2822 
2823  while (i < max_equal && toupper(prevstr[i]) == toupper(retstr[i])) {
2824  i++;
2825  }
2826 
2827  max_equal = i;
2828  prevstr = retstr;
2829  ++which;
2830  }
2831 
2832  /* Insert longest match to position 0. */
2833  retstr = ast_strndup(AST_VECTOR_GET(vec, 0), max_equal);
2834  if (!retstr || AST_VECTOR_INSERT_AT(vec, 0, retstr)) {
2835  ast_free(retstr);
2836 
2837  goto vector_cleanup;
2838  }
2839 
2840  return vec;
2841 
2842 vector_cleanup:
2844  AST_VECTOR_PTR_FREE(vec);
2845 
2846  return NULL;
2847 }
2848 
2849 /*! \brief returns true if there are more words to match */
2850 static int more_words (const char * const *dst)
2851 {
2852  int i;
2853  for (i = 0; dst[i]; i++) {
2854  if (dst[i][0] != '[')
2855  return -1;
2856  }
2857  return 0;
2858 }
2859 
2860 /*
2861  * generate the entry at position 'state'
2862  */
2863 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock)
2864 {
2865  const char *argv[AST_MAX_ARGS];
2866  struct ast_cli_entry *e = NULL;
2867  int x = 0, argindex, matchlen;
2868  int matchnum=0;
2869  char *ret = NULL;
2870  char matchstr[80] = "";
2871  int tws = 0;
2872  /* Split the argument into an array of words */
2873  char *duplicate = parse_args(text, &x, argv, ARRAY_LEN(argv), &tws);
2874 
2875  if (!duplicate) /* malloc error */
2876  return NULL;
2877 
2878  /* Compute the index of the last argument (could be an empty string) */
2879  argindex = (!ast_strlen_zero(word) && x>0) ? x-1 : x;
2880 
2881  /* rebuild the command, ignore terminating white space and flatten space */
2882  ast_join(matchstr, sizeof(matchstr)-1, argv);
2883  matchlen = strlen(matchstr);
2884  if (tws) {
2885  strcat(matchstr, " "); /* XXX */
2886  if (matchlen)
2887  matchlen++;
2888  }
2889  if (lock)
2891  while ( (e = cli_next(e)) ) {
2892  /* XXX repeated code */
2893  int src = 0, dst = 0, n = 0;
2894 
2895  if (e->command[0] == '_')
2896  continue;
2897 
2898  /*
2899  * Try to match words, up to and excluding the last word, which
2900  * is either a blank or something that we want to extend.
2901  */
2902  for (;src < argindex; dst++, src += n) {
2903  n = word_match(argv[src], e->cmda[dst]);
2904  if (n < 0)
2905  break;
2906  }
2907 
2908  if (src != argindex && more_words(e->cmda + dst)) /* not a match */
2909  continue;
2910  ret = is_prefix(argv[src], e->cmda[dst], state - matchnum, &n);
2911  matchnum += n; /* this many matches here */
2912  if (ret) {
2913  /*
2914  * argv[src] is a valid prefix of the next word in this
2915  * command. If this is also the correct entry, return it.
2916  */
2917  if (matchnum > state)
2918  break;
2919  ast_free(ret);
2920  ret = NULL;
2921  } else if (ast_strlen_zero(e->cmda[dst])) {
2922  /*
2923  * This entry is a prefix of the command string entered
2924  * (only one entry in the list should have this property).
2925  * Run the generator if one is available. In any case we are done.
2926  */
2927  if (e->handler) { /* new style command */
2928  struct ast_cli_args a = {
2929  .line = matchstr, .word = word,
2930  .pos = argindex,
2931  .n = state - matchnum,
2932  .argv = argv,
2933  .argc = x};
2934 
2935  /* If the command is in a module it must be running. */
2936  if (!e->module || ast_module_running_ref(e->module)) {
2937  ret = e->handler(e, CLI_GENERATE, &a);
2939  }
2940  }
2941  if (ret)
2942  break;
2943  }
2944  }
2945  if (lock)
2947  ast_free(duplicate);
2948  return ret;
2949 }
2950 
2951 char *ast_cli_generator(const char *text, const char *word, int state)
2952 {
2953  return __ast_cli_generator(text, word, state, 1);
2954 }
2955 
2956 static int allowed_on_shutdown(struct ast_cli_entry *e)
2957 {
2958  int found = 0;
2959  int i;
2960 
2962  for (i = 0; i < AST_VECTOR_SIZE(&shutdown_commands); ++i) {
2963  if (e == AST_VECTOR_GET(&shutdown_commands, i)) {
2964  found = 1;
2965  break;
2966  }
2967  }
2969 
2970  return found;
2971 }
2972 
2973 int ast_cli_command_full(int uid, int gid, int fd, const char *s)
2974 {
2975  const char *args[AST_MAX_ARGS + 1];
2976  struct ast_cli_entry *e = NULL;
2977  int x;
2978  char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL);
2979  char tmp[AST_MAX_ARGS + 1];
2980  char *retval = CLI_FAILURE;
2981  struct ast_cli_args a = {
2982  .fd = fd, .argc = x, .argv = args+1 };
2983 
2984  if (duplicate == NULL)
2985  return RESULT_FAILURE;
2986 
2987  if (x < 1) /* We need at least one entry, otherwise ignore */
2988  goto done;
2989 
2991  e = find_cli(args + 1, 0);
2992  if (e)
2995  if (e == NULL) {
2996  ast_cli(fd, "No such command '%s' (type 'core show help %s' for other possible commands)\n", s, find_best(args + 1));
2997  goto done;
2998  }
2999 
3000  if (ast_shutting_down() && !allowed_on_shutdown(e)) {
3001  ast_cli(fd, "Command '%s' cannot be run during shutdown\n", s);
3002  goto done;
3003  }
3004 
3005  ast_join(tmp, sizeof(tmp), args + 1);
3006  /* Check if the user has rights to run this command. */
3007  if (!cli_has_permissions(uid, gid, tmp)) {
3008  ast_cli(fd, "You don't have permissions to run '%s' command\n", tmp);
3009  goto done;
3010  }
3011 
3012  /*
3013  * Within the handler, argv[-1] contains a pointer to the ast_cli_entry.
3014  * Remember that the array returned by parse_args is NULL-terminated.
3015  */
3016  args[0] = (char *)e;
3017 
3018  /* If the command is in a module it must be running. */
3019  if (!e->module || ast_module_running_ref(e->module)) {
3020  retval = e->handler(e, CLI_HANDLER, &a);
3022  }
3023 
3024  if (retval == CLI_SHOWUSAGE) {
3025  ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
3026  } else if (retval == CLI_FAILURE) {
3027  ast_cli(fd, "Command '%s' failed.\n", s);
3028  }
3029 
3030 done:
3031  if (e) {
3032  ast_atomic_fetchadd_int(&e->inuse, -1);
3033  }
3034  ast_free(duplicate);
3036 }
3037 
3038 int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s)
3039 {
3040  char cmd[512];
3041  int x, y = 0, count = 0;
3042 
3043  for (x = 0; x < size; x++) {
3044  cmd[y] = s[x];
3045  y++;
3046  if (s[x] == '\0') {
3047  ast_cli_command_full(uid, gid, fd, cmd);
3048  y = 0;
3049  count++;
3050  }
3051  }
3052  return count;
3053 }
3054 
3055 void ast_cli_print_timestr_fromseconds(int fd, int seconds, const char *prefix)
3056 {
3057  print_uptimestr(fd, ast_tv(seconds, 0), prefix, 0);
3058 }
3059 
3061 {
3062  int res;
3063 
3067 
3068  return res;
3069 }
Prototypes for public functions only of internal interest,.
jack_status_t status
Definition: app_jack.c:146
ast_mutex_t lock
Definition: app_meetme.c:1093
char * text
Definition: app_queue.c:1641
#define var
Definition: ast_expr2f.c:614
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:1870
#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_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
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:3375
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:2312
static int usecnt
Definition: chan_ooh323.c:332
static const char type[]
Definition: chan_ooh323.c:109
enum sip_cc_notify_state state
Definition: chan_sip.c:966
static void dummy(char *unused,...)
Definition: chan_unistim.c:220
General Asterisk PBX channel definitions.
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
#define DEBUGCHAN_FLAG
Definition: channel.h:857
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:1272
unsigned int ast_channel_fin(const struct ast_channel *chan)
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1354
const char * ast_channel_uniqueid(const struct ast_channel *chan)
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1148
#define ast_channel_lock(chan)
Definition: channel.h:2922
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
const char * ast_channel_data(const struct ast_channel *chan)
struct ast_bridge * ast_channel_get_bridge(const struct ast_channel *chan)
Get the bridge associated with a channel.
Definition: channel.c:10720
ast_group_t ast_channel_pickupgroup(const struct ast_channel *chan)
const char * ast_channel_context(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
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
struct ast_trans_pvt * ast_channel_readtrans(const struct ast_channel *chan)
ast_callid ast_channel_callid(const struct ast_channel *chan)
unsigned long global_fin
Definition: channel.c:95
const char * ast_channel_name(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
const char * ast_channel_language(const struct ast_channel *chan)
unsigned int ast_channel_fout(const struct ast_channel *chan)
const char * ast_channel_linkedid(const struct ast_channel *chan)
const char * ast_channel_exten(const struct ast_channel *chan)
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2470
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1402
@ AST_CHAN_TP_INTERNAL
Channels with this particular technology are an implementation detail of Asterisk and should generall...
Definition: channel.h:971
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1416
struct ast_trans_pvt * ast_channel_writetrans(const struct ast_channel *chan)
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2958
ast_group_t ast_channel_callgroup(const struct ast_channel *chan)
struct ast_party_id ast_channel_connected_effective_id(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1448
const char * ast_channel_appl(const struct ast_channel *chan)
void ast_channel_fout_set(struct ast_channel *chan, unsigned int value)
struct varshead * ast_channel_varshead(struct ast_channel *chan)
unsigned long global_fout
Definition: channel.h:866
struct ast_stream_topology * ast_channel_get_stream_topology(const struct ast_channel *chan)
Retrieve the topology of streams on a channel.
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2923
const struct ast_channel_tech * ast_channel_tech(const 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:347
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)
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:86
@ AST_OPT_FLAG_DEBUG_MODULE
Definition: options.h:84
@ 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:2411
struct ast_group_info * ast_app_group_list_head(void)
Get the head of the group count list.
Definition: main/app.c:2406
int ast_app_group_list_rdlock(void)
Read Lock the group count list.
Definition: main/app.c:2401
char * strcasestr(const char *, const char *)
char * strsep(char **str, const char *delims)
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3327
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_STATUS_FILEUNCHANGED
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
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:3220
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
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:2038
void ast_console_toggle_mute(int fd, int silent)
mute or unmute a console from logging
Definition: asterisk.c:1268
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:2407
void ast_verb_console_set(int verb_level)
Set this thread's console verbosity level.
Definition: logger.c:2425
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_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:234
#define ast_rwlock_rdlock(a)
Definition: lock.h:233
#define AST_RWLOCK_DEFINE_STATIC(rwlock)
Definition: lock.h:541
#define ast_mutex_unlock(a)
Definition: lock.h:188
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:755
#define ast_mutex_trylock(a)
Definition: lock.h:189
#define ast_rwlock_unlock(a)
Definition: lock.h:232
#define ast_mutex_lock(a)
Definition: lock.h:187
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:518
#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_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:840
static char * handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1003
#define TRACE_HANDLER
Definition: main/cli.c:404
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:2704
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:1284
static void remove_shutdown_command(struct ast_cli_entry *e)
Definition: main/cli.c:2424
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:3055
static ast_rwlock_t shutdown_commands_lock
Definition: main/cli.c:112
static void cli_shutdown(void)
Definition: main/cli.c:2237
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:2431
#define AST_CLI_INITLEN
Initial buffer size for resulting strings in ast_cli()
Definition: main/cli.c:116
static char * group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1897
static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
Definition: main/cli.c:908
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:1862
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:1348
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:895
static int channel_set_debug(void *obj, void *arg, void *data, int flags)
Definition: main/cli.c:1484
#define FORMAT_STRING
#define HOUR
static int set_full_cmd(struct ast_cli_entry *e)
Definition: main/cli.c:2080
#define WEEK
static struct ast_cli_entry cli_cli[]
Definition: main/cli.c:2016
#define DAY
static char * handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:683
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: main/cli.c:2542
#define YEAR
static struct module_level_list debug_modules
Definition: main/cli.c:107
static struct module_level_list trace_modules
Definition: main/cli.c:108
#define DEBUG_HANDLER
Definition: main/cli.c:403
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:2300
#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 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_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1425
unsigned int ast_trace_get_by_module(const char *module)
Get the trace level for a module.
Definition: main/cli.c:153
#define VERBOSE_FORMAT_STRING2
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2760
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:2765
static char * handle_trace(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:630
void ast_cli(int fd, const char *fmt,...)
Definition: main/cli.c:118
static char * complete_number(const char *partial, unsigned int min, unsigned int max, int n)
Definition: main/cli.c:363
int __ast_cli_register(struct ast_cli_entry *e, struct ast_module *module)
Definition: main/cli.c:2454
static int word_match(const char *cmd, const char *cli_word)
Definition: main/cli.c:2261
static int allowed_on_shutdown(struct ast_cli_entry *e)
Definition: main/cli.c:2956
static char * handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1043
#define CONCISE_FORMAT_STRING
static char * handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1099
static const char cli_rsvd[]
Definition: main/cli.c:2074
static int cli_default_perm
Default permissions value 1=Permit 0=Deny.
Definition: main/cli.c:87
static char * handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:2586
static int more_words(const char *const *dst)
returns true if there are more words to match
Definition: main/cli.c:2850
static char * handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1642
static int cli_has_permissions(int uid, int gid, const char *command)
Definition: main/cli.c:183
#define MODLIST_FORMAT
Definition: main/cli.c:889
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:3060
static void destroy_user_perms(void)
cleanup (free) cli_perms linkedlist.
Definition: main/cli.c:2099
void ast_builtins_init(void)
initialize the _full_cmd string in * each of the builtins.
Definition: main/cli.c:2243
static int cli_completion_vector_add(struct ast_vector_string *vec, char *value)
Definition: main/cli.c:2739
static char * handle_cli_malloc_trim(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1988
static int climodentryfd
Definition: main/cli.c:893
static char * find_best(const char *argv[])
Definition: main/cli.c:2394
AST_THREADSTORAGE_RAW(completion_storage)
static char * handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:319
static char * handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1508
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:3038
static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:970
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
#define MODLIST_FORMAT2
Definition: main/cli.c:890
static void status_debug_verbose(struct ast_cli_args *a, int handler, int old_val, int cur_val)
Definition: main/cli.c:407
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:2951
static char * handle_debug_category(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1574
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
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:2556
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:1329
#define MINUTE
static char * handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1227
static ast_mutex_t climodentrylock
Definition: main/cli.c:892
static char * handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:572
static char * __ast_cli_generator(const char *text, const char *word, int state, int lock)
Definition: main/cli.c:2863
static char * handle_refresh(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:808
static struct @362 shutdown_commands
static char * parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
Definition: main/cli.c:2632
static int cli_is_registered(struct ast_cli_entry *e)
Definition: main/cli.c:2412
static struct ast_cli_entry * cli_next(struct ast_cli_entry *e)
Definition: main/cli.c:961
static char * handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1951
static char * handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:1615
int ast_cli_perms_init(int reload)
Definition: main/cli.c:2115
#define FORMAT_STRING2
static char * handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: main/cli.c:240
static const char perms_config[]
CLI permissions config file.
Definition: main/cli.c:85
char * ast_cli_complete(const char *word, const char *const choices[], int state)
Definition: main/cli.c:1843
unsigned int ast_debug_get_by_module(const char *module)
Get the debug level for a module.
Definition: main/cli.c:136
static struct ast_cli_entry * find_cli(const char *const cmds[], int match_type)
Definition: main/cli.c:2350
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:2973
#define VERBOSE_FORMAT_STRING
int __ast_cli_register_multiple(struct ast_cli_entry *e, int len, struct ast_module *module)
Definition: main/cli.c:2531
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:2567
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
const char * ast_module_support_level_to_string(enum ast_module_support_level support_level)
Definition: loader.c:2755
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode)
Unload a module.
Definition: loader.c:1229
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:1374
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:1819
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:455
@ 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:1562
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:4767
int ast_processed_calls(void)
Retrieve the total number of calls processed through the PBX since last restart.
Definition: pbx.c:4772
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
static int reload(void)
static uint16_t t1
Definition: res_pktccops.c:159
#define NULL
Definition: resample.c:96
Media Stream API.
struct ast_variable * ast_stream_get_metadata_list(const struct ast_stream *stream)
Get all stream metadata keys.
Definition: stream.c:439
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
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:1077
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_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:788
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
const char * ast_stream_state2str(enum ast_stream_state state)
Convert the state of a stream into a string.
Definition: stream.c:388
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
char * ast_skip_nonblanks(const char *str)
Gets a pointer to first whitespace character in a string.
Definition: strings.h:204
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:1117
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
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:1008
#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:826
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:640
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:711
#define ast_join(s, len, w)
Join an array of strings into a single string.
Definition: strings.h:501
@ AST_DYNSTR_BUILD_FAILED
Definition: strings.h:921
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:887
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
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
struct ast_cli_entry::@240 list
const char *const cmda[AST_MAX_CMD_LEN]
Definition: cli.h:172
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure used to handle boolean flags.
Definition: utils.h:199
channel group info
Definition: channel.h:2915
char * category
Definition: channel.h:2917
char * group
Definition: channel.h:2918
struct ast_channel * chan
Definition: channel.h:2916
struct ast_group_info::@238 group_list
Support for dynamic strings.
Definition: strings.h:604
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::@363 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::@364 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:115
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:105
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:157
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:233
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:928
FILE * out
Definition: utils/frame.c:33
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_assert(a)
Definition: utils.h:734
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: main/utils.c:1738
#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:661
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