Wed Jan 8 2020 09:49:46

Asterisk developer's documentation


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 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421600 $")
33 
34 #include "asterisk/_private.h"
35 #include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
36 #include <sys/signal.h>
37 #include <signal.h>
38 #include <ctype.h>
39 #include <regex.h>
40 #include <pwd.h>
41 #include <grp.h>
42 
43 #include "asterisk/cli.h"
44 #include "asterisk/linkedlists.h"
45 #include "asterisk/module.h"
46 #include "asterisk/pbx.h"
47 #include "asterisk/channel.h"
48 #include "asterisk/utils.h"
49 #include "asterisk/app.h"
50 #include "asterisk/lock.h"
51 #include "editline/readline/readline.h"
52 #include "asterisk/threadstorage.h"
53 #include "asterisk/translate.h"
54 
55 /*!
56  * \brief List of restrictions per user.
57  */
58 struct cli_perm {
59  unsigned int permit:1; /*!< 1=Permit 0=Deny */
60  char *command; /*!< Command name (to apply restrictions) */
62 };
63 
65 
66 /*! \brief list of users to apply restrictions. */
68  int uid; /*!< User ID (-1 disabled) */
69  int gid; /*!< Group ID (-1 disabled) */
70  struct cli_perm_head *perms; /*!< List of permissions. */
71  AST_LIST_ENTRY(usergroup_cli_perm) list;/*!< List mechanics */
72 };
73 /*! \brief CLI permissions config file. */
74 static const char perms_config[] = "cli_permissions.conf";
75 /*! \brief Default permissions value 1=Permit 0=Deny */
76 static int cli_default_perm = 1;
77 
78 /*! \brief mutex used to prevent a user from running the 'cli reload permissions' command while
79  * it is already running. */
81 /*! \brief List of users and permissions. */
82 static AST_RWLIST_HEAD_STATIC(cli_perms, usergroup_cli_perm);
83 
84 /*!
85  * \brief map a debug or verbose level to a module name
86  */
87 struct module_level {
88  unsigned int level;
89  AST_RWLIST_ENTRY(module_level) entry;
90  char module[0];
91 };
92 
94 
95 /*! list of module names and their debug levels */
96 static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;
97 /*! list of module names and their verbose levels */
98 static struct module_level_list verbose_modules = AST_RWLIST_HEAD_INIT_VALUE;
99 
101 
102 /*! \brief Initial buffer size for resulting strings in ast_cli() */
103 #define AST_CLI_INITLEN 256
104 
105 void ast_cli(int fd, const char *fmt, ...)
106 {
107  int res;
108  struct ast_str *buf;
109  va_list ap;
110 
111  if (!(buf = ast_str_thread_get(&ast_cli_buf, AST_CLI_INITLEN)))
112  return;
113 
114  va_start(ap, fmt);
115  res = ast_str_set_va(&buf, 0, fmt, ap);
116  va_end(ap);
117 
118  if (res != AST_DYNSTR_BUILD_FAILED) {
119  ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
120  }
121 }
122 
123 unsigned int ast_debug_get_by_module(const char *module)
124 {
125  struct module_level *ml;
126  unsigned int res = 0;
127 
129  AST_LIST_TRAVERSE(&debug_modules, ml, entry) {
130  if (!strcasecmp(ml->module, module)) {
131  res = ml->level;
132  break;
133  }
134  }
136 
137  return res;
138 }
139 
140 unsigned int ast_verbose_get_by_module(const char *module)
141 {
142  struct module_level *ml;
143  unsigned int res = 0;
144 
146  AST_LIST_TRAVERSE(&verbose_modules, ml, entry) {
147  if (!strcasecmp(ml->module, module)) {
148  res = ml->level;
149  break;
150  }
151  }
153 
154  return res;
155 }
156 
157 /*! \internal
158  * \brief Check if the user with 'uid' and 'gid' is allow to execute 'command',
159  * if command starts with '_' then not check permissions, just permit
160  * to run the 'command'.
161  * if uid == -1 or gid == -1 do not check permissions.
162  * if uid == -2 and gid == -2 is because rasterisk client didn't send
163  * the credentials, so the cli_default_perm will be applied.
164  * \param uid User ID.
165  * \param gid Group ID.
166  * \param command Command name to check permissions.
167  * \retval 1 if has permission
168  * \retval 0 if it is not allowed.
169  */
170 static int cli_has_permissions(int uid, int gid, const char *command)
171 {
172  struct usergroup_cli_perm *user_perm;
173  struct cli_perm *perm;
174  /* set to the default permissions general option. */
175  int isallowg = cli_default_perm, isallowu = -1, ispattern;
176  regex_t regexbuf;
177 
178  /* if uid == -1 or gid == -1 do not check permissions.
179  if uid == -2 and gid == -2 is because rasterisk client didn't send
180  the credentials, so the cli_default_perm will be applied. */
181  if ((uid == CLI_NO_PERMS && gid == CLI_NO_PERMS) || command[0] == '_') {
182  return 1;
183  }
184 
185  if (gid < 0 && uid < 0) {
186  return cli_default_perm;
187  }
188 
189  AST_RWLIST_RDLOCK(&cli_perms);
190  AST_LIST_TRAVERSE(&cli_perms, user_perm, list) {
191  if (user_perm->gid != gid && user_perm->uid != uid) {
192  continue;
193  }
194  AST_LIST_TRAVERSE(user_perm->perms, perm, list) {
195  if (strcasecmp(perm->command, "all") && strncasecmp(perm->command, command, strlen(perm->command))) {
196  /* if the perm->command is a pattern, check it against command. */
197  ispattern = !regcomp(&regexbuf, perm->command, REG_EXTENDED | REG_NOSUB | REG_ICASE);
198  if (ispattern && regexec(&regexbuf, command, 0, NULL, 0)) {
199  regfree(&regexbuf);
200  continue;
201  }
202  if (!ispattern) {
203  continue;
204  }
205  regfree(&regexbuf);
206  }
207  if (user_perm->uid == uid) {
208  /* this is a user definition. */
209  isallowu = perm->permit;
210  } else {
211  /* otherwise is a group definition. */
212  isallowg = perm->permit;
213  }
214  }
215  }
216  AST_RWLIST_UNLOCK(&cli_perms);
217  if (isallowu > -1) {
218  /* user definition override group definition. */
219  isallowg = isallowu;
220  }
221 
222  return isallowg;
223 }
224 
226 
227 static char *complete_fn(const char *word, int state)
228 {
229  char *c, *d;
230  char filename[PATH_MAX];
231 
232  if (word[0] == '/')
233  ast_copy_string(filename, word, sizeof(filename));
234  else
235  snprintf(filename, sizeof(filename), "%s/%s", ast_config_AST_MODULE_DIR, word);
236 
237  c = d = filename_completion_function(filename, state);
238 
239  if (c && word[0] != '/')
240  c += (strlen(ast_config_AST_MODULE_DIR) + 1);
241  if (c)
242  c = ast_strdup(c);
243 
244  ast_std_free(d);
245 
246  return c;
247 }
248 
249 static char *handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
250 {
251  /* "module load <mod>" */
252  switch (cmd) {
253  case CLI_INIT:
254  e->command = "module load";
255  e->usage =
256  "Usage: module load <module name>\n"
257  " Loads the specified module into Asterisk.\n";
258  return NULL;
259 
260  case CLI_GENERATE:
261  if (a->pos != e->args)
262  return NULL;
263  return complete_fn(a->word, a->n);
264  }
265  if (a->argc != e->args + 1)
266  return CLI_SHOWUSAGE;
267  if (ast_load_resource(a->argv[e->args])) {
268  ast_cli(a->fd, "Unable to load module %s\n", a->argv[e->args]);
269  return CLI_FAILURE;
270  }
271  ast_cli(a->fd, "Loaded %s\n", a->argv[e->args]);
272  return CLI_SUCCESS;
273 }
274 
275 static char *handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
276 {
277  int x;
278 
279  switch (cmd) {
280  case CLI_INIT:
281  e->command = "module reload";
282  e->usage =
283  "Usage: module reload [module ...]\n"
284  " Reloads configuration files for all listed modules which support\n"
285  " reloading, or for all supported modules if none are listed.\n";
286  return NULL;
287 
288  case CLI_GENERATE:
289  return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 1);
290  }
291  if (a->argc == e->args) {
292  ast_module_reload(NULL);
293  return CLI_SUCCESS;
294  }
295  for (x = e->args; x < a->argc; x++) {
296  int res = ast_module_reload(a->argv[x]);
297  /* XXX reload has multiple error returns, including -1 on error and 2 on success */
298  switch (res) {
299  case 0:
300  ast_cli(a->fd, "No such module '%s'\n", a->argv[x]);
301  break;
302  case 1:
303  ast_cli(a->fd, "Module '%s' does not support reload\n", a->argv[x]);
304  break;
305  }
306  }
307  return CLI_SUCCESS;
308 }
309 
310 static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
311 {
312  switch (cmd) {
313  case CLI_INIT:
314  e->command = "core reload";
315  e->usage =
316  "Usage: core reload\n"
317  " Execute a global reload.\n";
318  return NULL;
319 
320  case CLI_GENERATE:
321  return NULL;
322  }
323 
324  if (a->argc != e->args) {
325  return CLI_SHOWUSAGE;
326  }
327 
328  ast_module_reload(NULL);
329 
330  return CLI_SUCCESS;
331 }
332 /*!
333  * \brief Find the debug or verbose file setting
334  * \arg debug 1 for debug, 0 for verbose
335  */
336 static struct module_level *find_module_level(const char *module, unsigned int debug)
337 {
338  struct module_level *ml;
339  struct module_level_list *mll = debug ? &debug_modules : &verbose_modules;
340 
341  AST_LIST_TRAVERSE(mll, ml, entry) {
342  if (!strcasecmp(ml->module, module))
343  return ml;
344  }
345 
346  return NULL;
347 }
348 
349 static char *complete_number(const char *partial, unsigned int min, unsigned int max, int n)
350 {
351  int i, count = 0;
352  unsigned int prospective[2];
353  unsigned int part = strtoul(partial, NULL, 10);
354  char next[12];
355 
356  if (part < min || part > max) {
357  return NULL;
358  }
359 
360  for (i = 0; i < 21; i++) {
361  if (i == 0) {
362  prospective[0] = prospective[1] = part;
363  } else if (part == 0 && !ast_strlen_zero(partial)) {
364  break;
365  } else if (i < 11) {
366  prospective[0] = prospective[1] = part * 10 + (i - 1);
367  } else {
368  prospective[0] = (part * 10 + (i - 11)) * 10;
369  prospective[1] = prospective[0] + 9;
370  }
371  if (i < 11 && (prospective[0] < min || prospective[0] > max)) {
372  continue;
373  } else if (prospective[1] < min || prospective[0] > max) {
374  continue;
375  }
376 
377  if (++count > n) {
378  if (i < 11) {
379  snprintf(next, sizeof(next), "%u", prospective[0]);
380  } else {
381  snprintf(next, sizeof(next), "%u...", prospective[0] / 10);
382  }
383  return ast_strdup(next);
384  }
385  }
386  return NULL;
387 }
388 
389 static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
390 {
391  int oldval;
392  int newlevel;
393  unsigned int is_debug;
394  int atleast = 0;
395  int fd = a->fd;
396  int argc = a->argc;
397  const char * const *argv = a->argv;
398  const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
399  int *dst;
400  char *what;
401  struct module_level_list *mll;
402  struct module_level *ml;
403 
404  switch (cmd) {
405  case CLI_INIT:
406  e->command = "core set {debug|verbose}";
407  e->usage =
408 #if !defined(LOW_MEMORY)
409  "Usage: core set {debug|verbose} [atleast] <level> [module]\n"
410 #else
411  "Usage: core set {debug|verbose} [atleast] <level>\n"
412 #endif
413  " core set {debug|verbose} off\n"
414 #if !defined(LOW_MEMORY)
415  " Sets level of debug or verbose messages to be displayed or\n"
416  " sets a module name to display debug messages from.\n"
417 #else
418  " Sets level of debug or verbose messages to be displayed.\n"
419 #endif
420  " 0 or off means no messages should be displayed.\n"
421  " Equivalent to -d[d[...]] or -v[v[v...]] on startup\n";
422  return NULL;
423 
424  case CLI_GENERATE:
425  if (a->pos == 3 || (a->pos == 4 && !strcasecmp(a->argv[3], "atleast"))) {
426  const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
427  int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
428  if (a->n < 21 && numbermatch == 0) {
429  return complete_number(pos, 0, 0x7fffffff, a->n);
430  } else if (pos[0] == '0') {
431  if (a->n == 0) {
432  return ast_strdup("0");
433  } else {
434  return NULL;
435  }
436  } else if (a->n == (21 - numbermatch)) {
437  if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
438  return ast_strdup("off");
439  } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
440  return ast_strdup("atleast");
441  }
442  } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
443  return ast_strdup("atleast");
444  }
445 #if !defined(LOW_MEMORY)
446  } else if (a->pos == 4 || (a->pos == 5 && !strcasecmp(argv3, "atleast"))) {
447  return ast_complete_source_filename(a->pos == 4 ? S_OR(a->argv[4], "") : S_OR(a->argv[5], ""), a->n);
448 #endif
449  }
450  return NULL;
451  }
452  /* all the above return, so we proceed with the handler.
453  * we are guaranteed to be called with argc >= e->args;
454  */
455 
456  if (argc <= e->args)
457  return CLI_SHOWUSAGE;
458  if (!strcasecmp(argv[e->args - 1], "debug")) {
459  dst = &option_debug;
460  oldval = option_debug;
461  what = "Core debug";
462  is_debug = 1;
463  } else {
464  dst = &option_verbose;
465  oldval = option_verbose;
466  what = "Verbosity";
467  is_debug = 0;
468  }
469  if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
470  newlevel = 0;
471 
472  mll = is_debug ? &debug_modules : &verbose_modules;
473 
474  AST_RWLIST_WRLOCK(mll);
475  while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
476  ast_free(ml);
477  }
479  AST_RWLIST_UNLOCK(mll);
480 
481  goto done;
482  }
483  if (!strcasecmp(argv[e->args], "atleast"))
484  atleast = 1;
485  if (argc != e->args + atleast + 1 && argc != e->args + atleast + 2)
486  return CLI_SHOWUSAGE;
487  if (sscanf(argv[e->args + atleast], "%30d", &newlevel) != 1)
488  return CLI_SHOWUSAGE;
489  if (argc == e->args + atleast + 2) {
490  /* We have specified a module name. */
491  char *mod = ast_strdupa(argv[e->args + atleast + 1]);
492 
493  if ((strlen(mod) > 3) && !strcasecmp(mod + strlen(mod) - 3, ".so")) {
494  mod[strlen(mod) - 3] = '\0';
495  }
496 
497  mll = is_debug ? &debug_modules : &verbose_modules;
498 
499  AST_RWLIST_WRLOCK(mll);
500 
501  ml = find_module_level(mod, is_debug);
502  if (!newlevel) {
503  if (!ml) {
504  /* Specified off for a nonexistent entry. */
505  AST_RWLIST_UNLOCK(mll);
506  return CLI_SUCCESS;
507  }
508  AST_RWLIST_REMOVE(mll, ml, entry);
509  if (AST_RWLIST_EMPTY(mll))
511  AST_RWLIST_UNLOCK(mll);
512  ast_cli(fd, "%s was %u and has been set to 0 for '%s'\n", what, ml->level, mod);
513  ast_free(ml);
514  return CLI_SUCCESS;
515  }
516 
517  if (ml) {
518  if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
519  ast_cli(fd, "%s is %u for '%s'\n", what, ml->level, mod);
520  AST_RWLIST_UNLOCK(mll);
521  return CLI_SUCCESS;
522  }
523  oldval = ml->level;
524  ml->level = newlevel;
525  } else {
526  ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
527  if (!ml) {
528  AST_RWLIST_UNLOCK(mll);
529  return CLI_FAILURE;
530  }
531  oldval = ml->level;
532  ml->level = newlevel;
533  strcpy(ml->module, mod);
534  AST_RWLIST_INSERT_TAIL(mll, ml, entry);
535  }
536 
538 
539  AST_RWLIST_UNLOCK(mll);
540 
541  ast_cli(fd, "%s was %d and has been set to %u for '%s'\n", what, oldval, ml->level, ml->module);
542 
543  return CLI_SUCCESS;
544  } else if (!newlevel) {
545  /* Specified level as 0 instead of off. */
546  mll = is_debug ? &debug_modules : &verbose_modules;
547 
548  AST_RWLIST_WRLOCK(mll);
549  while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
550  ast_free(ml);
551  }
553  AST_RWLIST_UNLOCK(mll);
554  }
555 
556 done:
557  if (!atleast || newlevel > *dst)
558  *dst = newlevel;
559  if (oldval > 0 && *dst == 0)
560  ast_cli(fd, "%s is now OFF\n", what);
561  else if (*dst > 0) {
562  if (oldval == *dst)
563  ast_cli(fd, "%s is at least %d\n", what, *dst);
564  else
565  ast_cli(fd, "%s was %d and is now %d\n", what, oldval, *dst);
566  }
567 
568  return CLI_SUCCESS;
569 }
570 
571 static char *handle_logger_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
572 {
573  switch (cmd) {
574  case CLI_INIT:
575  e->command = "logger mute";
576  e->usage =
577  "Usage: logger mute\n"
578  " Disables logging output to the current console, making it possible to\n"
579  " gather information without being disturbed by scrolling lines.\n";
580  return NULL;
581  case CLI_GENERATE:
582  return NULL;
583  }
584 
585  if (a->argc < 2 || a->argc > 3)
586  return CLI_SHOWUSAGE;
587 
588  if (a->argc == 3 && !strcasecmp(a->argv[2], "silent"))
590  else
592 
593  return CLI_SUCCESS;
594 }
595 
596 static char *handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
597 {
598  /* "module unload mod_1 [mod_2 .. mod_N]" */
599  int x;
600  int force = AST_FORCE_SOFT;
601  const char *s;
602 
603  switch (cmd) {
604  case CLI_INIT:
605  e->command = "module unload";
606  e->usage =
607  "Usage: module unload [-f|-h] <module_1> [<module_2> ... ]\n"
608  " Unloads the specified module from Asterisk. The -f\n"
609  " option causes the module to be unloaded even if it is\n"
610  " in use (may cause a crash) and the -h module causes the\n"
611  " module to be unloaded even if the module says it cannot, \n"
612  " which almost always will cause a crash.\n";
613  return NULL;
614 
615  case CLI_GENERATE:
616  return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
617  }
618  if (a->argc < e->args + 1)
619  return CLI_SHOWUSAGE;
620  x = e->args; /* first argument */
621  s = a->argv[x];
622  if (s[0] == '-') {
623  if (s[1] == 'f')
624  force = AST_FORCE_FIRM;
625  else if (s[1] == 'h')
626  force = AST_FORCE_HARD;
627  else
628  return CLI_SHOWUSAGE;
629  if (a->argc < e->args + 2) /* need at least one module name */
630  return CLI_SHOWUSAGE;
631  x++; /* skip this argument */
632  }
633 
634  for (; x < a->argc; x++) {
635  if (ast_unload_resource(a->argv[x], force)) {
636  ast_cli(a->fd, "Unable to unload resource %s\n", a->argv[x]);
637  return CLI_FAILURE;
638  }
639  ast_cli(a->fd, "Unloaded %s\n", a->argv[x]);
640  }
641 
642  return CLI_SUCCESS;
643 }
644 
645 #define MODLIST_FORMAT "%-30s %-40.40s %-10d\n"
646 #define MODLIST_FORMAT2 "%-30s %-40.40s %-10s\n"
647 
649 static int climodentryfd = -1;
650 
651 static int modlist_modentry(const char *module, const char *description, int usecnt, const char *like)
652 {
653  /* Comparing the like with the module */
654  if (strcasestr(module, like) ) {
655  ast_cli(climodentryfd, MODLIST_FORMAT, module, description, usecnt);
656  return 1;
657  }
658  return 0;
659 }
660 
661 static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
662 {
663  int x; /* the main part - years, weeks, etc. */
664  struct ast_str *out;
665 
666 #define SECOND (1)
667 #define MINUTE (SECOND*60)
668 #define HOUR (MINUTE*60)
669 #define DAY (HOUR*24)
670 #define WEEK (DAY*7)
671 #define YEAR (DAY*365)
672 #define NEEDCOMMA(x) ((x)? ",": "") /* define if we need a comma */
673  if (timeval.tv_sec < 0) /* invalid, nothing to show */
674  return;
675 
676  if (printsec) { /* plain seconds output */
677  ast_cli(fd, "%s: %lu\n", prefix, (u_long)timeval.tv_sec);
678  return;
679  }
680  out = ast_str_alloca(256);
681  if (timeval.tv_sec > YEAR) {
682  x = (timeval.tv_sec / YEAR);
683  timeval.tv_sec -= (x * YEAR);
684  ast_str_append(&out, 0, "%d year%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
685  }
686  if (timeval.tv_sec > WEEK) {
687  x = (timeval.tv_sec / WEEK);
688  timeval.tv_sec -= (x * WEEK);
689  ast_str_append(&out, 0, "%d week%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
690  }
691  if (timeval.tv_sec > DAY) {
692  x = (timeval.tv_sec / DAY);
693  timeval.tv_sec -= (x * DAY);
694  ast_str_append(&out, 0, "%d day%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
695  }
696  if (timeval.tv_sec > HOUR) {
697  x = (timeval.tv_sec / HOUR);
698  timeval.tv_sec -= (x * HOUR);
699  ast_str_append(&out, 0, "%d hour%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
700  }
701  if (timeval.tv_sec > MINUTE) {
702  x = (timeval.tv_sec / MINUTE);
703  timeval.tv_sec -= (x * MINUTE);
704  ast_str_append(&out, 0, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval.tv_sec));
705  }
706  x = timeval.tv_sec;
707  if (x > 0 || ast_str_strlen(out) == 0) /* if there is nothing, print 0 seconds */
708  ast_str_append(&out, 0, "%d second%s ", x, ESS(x));
709  ast_cli(fd, "%s: %s\n", prefix, ast_str_buffer(out));
710 }
711 
712 static struct ast_cli_entry *cli_next(struct ast_cli_entry *e)
713 {
714  if (e) {
715  return AST_LIST_NEXT(e, list);
716  } else {
717  return AST_LIST_FIRST(&helpers);
718  }
719 }
720 
721 static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
722 {
723  struct timeval curtime = ast_tvnow();
724  int printsec;
725 
726  switch (cmd) {
727  case CLI_INIT:
728  e->command = "core show uptime [seconds]";
729  e->usage =
730  "Usage: core show uptime [seconds]\n"
731  " Shows Asterisk uptime information.\n"
732  " The seconds word returns the uptime in seconds only.\n";
733  return NULL;
734 
735  case CLI_GENERATE:
736  return NULL;
737  }
738  /* regular handler */
739  if (a->argc == e->args && !strcasecmp(a->argv[e->args-1],"seconds"))
740  printsec = 1;
741  else if (a->argc == e->args-1)
742  printsec = 0;
743  else
744  return CLI_SHOWUSAGE;
745  if (ast_startuptime.tv_sec)
746  print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec);
747  if (ast_lastreloadtime.tv_sec)
748  print_uptimestr(a->fd, ast_tvsub(curtime, ast_lastreloadtime), "Last reload", printsec);
749  return CLI_SUCCESS;
750 }
751 
752 static char *handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
753 {
754  const char *like;
755 
756  switch (cmd) {
757  case CLI_INIT:
758  e->command = "module show [like]";
759  e->usage =
760  "Usage: module show [like keyword]\n"
761  " Shows Asterisk modules currently in use, and usage statistics.\n";
762  return NULL;
763 
764  case CLI_GENERATE:
765  if (a->pos == e->args)
766  return ast_module_helper(a->line, a->word, a->pos, a->n, a->pos, 0);
767  else
768  return NULL;
769  }
770  /* all the above return, so we proceed with the handler.
771  * we are guaranteed to have argc >= e->args
772  */
773  if (a->argc == e->args - 1)
774  like = "";
775  else if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args-1], "like") )
776  like = a->argv[e->args];
777  else
778  return CLI_SHOWUSAGE;
779 
781  climodentryfd = a->fd; /* global, protected by climodentrylock */
782  ast_cli(a->fd, MODLIST_FORMAT2, "Module", "Description", "Use Count");
783  ast_cli(a->fd,"%d modules loaded\n", ast_update_module_list(modlist_modentry, like));
784  climodentryfd = -1;
786  return CLI_SUCCESS;
787 }
788 #undef MODLIST_FORMAT
789 #undef MODLIST_FORMAT2
790 
791 static char *handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
792 {
793  struct timeval curtime = ast_tvnow();
794  int showuptime, printsec;
795 
796  switch (cmd) {
797  case CLI_INIT:
798  e->command = "core show calls [uptime]";
799  e->usage =
800  "Usage: core show calls [uptime] [seconds]\n"
801  " Lists number of currently active calls and total number of calls\n"
802  " processed through PBX since last restart. If 'uptime' is specified\n"
803  " the system uptime is also displayed. If 'seconds' is specified in\n"
804  " addition to 'uptime', the system uptime is displayed in seconds.\n";
805  return NULL;
806 
807  case CLI_GENERATE:
808  if (a->pos != e->args)
809  return NULL;
810  return a->n == 0 ? ast_strdup("seconds") : NULL;
811  }
812 
813  /* regular handler */
814  if (a->argc >= e->args && !strcasecmp(a->argv[e->args-1],"uptime")) {
815  showuptime = 1;
816 
817  if (a->argc == e->args+1 && !strcasecmp(a->argv[e->args],"seconds"))
818  printsec = 1;
819  else if (a->argc == e->args)
820  printsec = 0;
821  else
822  return CLI_SHOWUSAGE;
823  } else if (a->argc == e->args-1) {
824  showuptime = 0;
825  printsec = 0;
826  } else
827  return CLI_SHOWUSAGE;
828 
829  if (option_maxcalls) {
830  ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
832  ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
833  } else {
834  ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
835  }
836 
837  ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
838 
839  if (ast_startuptime.tv_sec && showuptime) {
840  print_uptimestr(a->fd, ast_tvsub(curtime, ast_startuptime), "System uptime", printsec);
841  }
842 
843  return RESULT_SUCCESS;
844 }
845 
846 static char *handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
847 {
848 #define FORMAT_STRING "%-20.20s %-20.20s %-7.7s %-30.30s\n"
849 #define FORMAT_STRING2 "%-20.20s %-20.20s %-7.7s %-30.30s\n"
850 #define CONCISE_FORMAT_STRING "%s!%s!%s!%d!%s!%s!%s!%s!%s!%s!%d!%s!%s!%s\n"
851 #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"
852 #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"
853 
854  struct ast_channel *c = NULL;
855  int numchans = 0, concise = 0, verbose = 0, count = 0;
856  struct ast_channel_iterator *iter = NULL;
857 
858  switch (cmd) {
859  case CLI_INIT:
860  e->command = "core show channels [concise|verbose|count]";
861  e->usage =
862  "Usage: core show channels [concise|verbose|count]\n"
863  " Lists currently defined channels and some information about them. If\n"
864  " 'concise' is specified, the format is abridged and in a more easily\n"
865  " machine parsable format. If 'verbose' is specified, the output includes\n"
866  " more and longer fields. If 'count' is specified only the channel and call\n"
867  " count is output.\n"
868  " The 'concise' option is deprecated and will be removed from future versions\n"
869  " of Asterisk.\n";
870  return NULL;
871 
872  case CLI_GENERATE:
873  return NULL;
874  }
875 
876  if (a->argc == e->args) {
877  if (!strcasecmp(a->argv[e->args-1],"concise"))
878  concise = 1;
879  else if (!strcasecmp(a->argv[e->args-1],"verbose"))
880  verbose = 1;
881  else if (!strcasecmp(a->argv[e->args-1],"count"))
882  count = 1;
883  else
884  return CLI_SHOWUSAGE;
885  } else if (a->argc != e->args - 1)
886  return CLI_SHOWUSAGE;
887 
888  if (!count) {
889  if (!concise && !verbose)
890  ast_cli(a->fd, FORMAT_STRING2, "Channel", "Location", "State", "Application(Data)");
891  else if (verbose)
892  ast_cli(a->fd, VERBOSE_FORMAT_STRING2, "Channel", "Context", "Extension", "Priority", "State", "Application", "Data",
893  "CallerID", "Duration", "Accountcode", "PeerAccount", "BridgedTo");
894  }
895 
896  if (!count && !(iter = ast_channel_iterator_all_new())) {
897  return CLI_FAILURE;
898  }
899 
900  for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
901  struct ast_channel *bc;
902  char durbuf[10] = "-";
903 
904  ast_channel_lock(c);
905 
906  bc = ast_bridged_channel(c);
907 
908  if (!count) {
909  if ((concise || verbose) && c->cdr && !ast_tvzero(c->cdr->start)) {
910  int duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
911  if (verbose) {
912  int durh = duration / 3600;
913  int durm = (duration % 3600) / 60;
914  int durs = duration % 60;
915  snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
916  } else {
917  snprintf(durbuf, sizeof(durbuf), "%d", duration);
918  }
919  }
920  if (concise) {
921  ast_cli(a->fd, CONCISE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
922  c->appl ? c->appl : "(None)",
923  S_OR(c->data, ""), /* XXX different from verbose ? */
924  S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""),
925  S_OR(c->accountcode, ""),
926  S_OR(c->peeraccount, ""),
927  c->amaflags,
928  durbuf,
929  bc ? bc->name : "(None)",
930  c->uniqueid);
931  } else if (verbose) {
932  ast_cli(a->fd, VERBOSE_FORMAT_STRING, c->name, c->context, c->exten, c->priority, ast_state2str(c->_state),
933  c->appl ? c->appl : "(None)",
934  c->data ? S_OR(c->data, "(Empty)" ): "(None)",
935  S_COR(c->caller.id.number.valid, c->caller.id.number.str, ""),
936  durbuf,
937  S_OR(c->accountcode, ""),
938  S_OR(c->peeraccount, ""),
939  bc ? bc->name : "(None)");
940  } else {
941  char locbuf[40] = "(None)";
942  char appdata[40] = "(None)";
943 
944  if (!ast_strlen_zero(c->context) && !ast_strlen_zero(c->exten))
945  snprintf(locbuf, sizeof(locbuf), "%s@%s:%d", c->exten, c->context, c->priority);
946  if (c->appl)
947  snprintf(appdata, sizeof(appdata), "%s(%s)", c->appl, S_OR(c->data, ""));
948  ast_cli(a->fd, FORMAT_STRING, c->name, locbuf, ast_state2str(c->_state), appdata);
949  }
950  }
952  }
953 
954  if (iter) {
956  }
957 
958  if (!concise) {
959  numchans = ast_active_channels();
960  ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
961  if (option_maxcalls)
962  ast_cli(a->fd, "%d of %d max active call%s (%5.2f%% of capacity)\n",
964  ((double)ast_active_calls() / (double)option_maxcalls) * 100.0);
965  else
966  ast_cli(a->fd, "%d active call%s\n", ast_active_calls(), ESS(ast_active_calls()));
967 
968  ast_cli(a->fd, "%d call%s processed\n", ast_processed_calls(), ESS(ast_processed_calls()));
969  }
970 
971  return CLI_SUCCESS;
972 
973 #undef FORMAT_STRING
974 #undef FORMAT_STRING2
975 #undef CONCISE_FORMAT_STRING
976 #undef VERBOSE_FORMAT_STRING
977 #undef VERBOSE_FORMAT_STRING2
978 }
979 
980 static char *handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
981 {
982  struct ast_channel *c=NULL;
983 
984  switch (cmd) {
985  case CLI_INIT:
986  e->command = "channel request hangup";
987  e->usage =
988  "Usage: channel request hangup <channel>|<all>\n"
989  " Request that a channel be hung up. The hangup takes effect\n"
990  " the next time the driver reads or writes from the channel.\n"
991  " If 'all' is specified instead of a channel name, all channels\n"
992  " will see the hangup request.\n";
993  return NULL;
994  case CLI_GENERATE:
995  return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
996  }
997 
998  if (a->argc != 4) {
999  return CLI_SHOWUSAGE;
1000  }
1001 
1002  if (!strcasecmp(a->argv[3], "all")) {
1003  struct ast_channel_iterator *iter = NULL;
1004  if (!(iter = ast_channel_iterator_all_new())) {
1005  return CLI_FAILURE;
1006  }
1007  for (; iter && (c = ast_channel_iterator_next(iter)); ast_channel_unref(c)) {
1008  ast_channel_lock(c);
1009  ast_cli(a->fd, "Requested Hangup on channel '%s'\n", c->name);
1011  ast_channel_unlock(c);
1012  }
1014  } else if ((c = ast_channel_get_by_name(a->argv[3]))) {
1015  ast_channel_lock(c);
1016  ast_cli(a->fd, "Requested Hangup on channel '%s'\n", c->name);
1018  ast_channel_unlock(c);
1019  c = ast_channel_unref(c);
1020  } else {
1021  ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
1022  }
1023 
1024  return CLI_SUCCESS;
1025 }
1026 
1027 /*! \brief handles CLI command 'cli show permissions' */
1028 static char *handle_cli_show_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1029 {
1030  struct usergroup_cli_perm *cp;
1031  struct cli_perm *perm;
1032  struct passwd *pw = NULL;
1033  struct group *gr = NULL;
1034 
1035  switch (cmd) {
1036  case CLI_INIT:
1037  e->command = "cli show permissions";
1038  e->usage =
1039  "Usage: cli show permissions\n"
1040  " Shows CLI configured permissions.\n";
1041  return NULL;
1042  case CLI_GENERATE:
1043  return NULL;
1044  }
1045 
1046  AST_RWLIST_RDLOCK(&cli_perms);
1047  AST_LIST_TRAVERSE(&cli_perms, cp, list) {
1048  if (cp->uid >= 0) {
1049  pw = getpwuid(cp->uid);
1050  if (pw) {
1051  ast_cli(a->fd, "user: %s [uid=%d]\n", pw->pw_name, cp->uid);
1052  }
1053  } else {
1054  gr = getgrgid(cp->gid);
1055  if (gr) {
1056  ast_cli(a->fd, "group: %s [gid=%d]\n", gr->gr_name, cp->gid);
1057  }
1058  }
1059  ast_cli(a->fd, "Permissions:\n");
1060  if (cp->perms) {
1061  AST_LIST_TRAVERSE(cp->perms, perm, list) {
1062  ast_cli(a->fd, "\t%s -> %s\n", perm->permit ? "permit" : "deny", perm->command);
1063  }
1064  }
1065  ast_cli(a->fd, "\n");
1066  }
1067  AST_RWLIST_UNLOCK(&cli_perms);
1068 
1069  return CLI_SUCCESS;
1070 }
1071 
1072 /*! \brief handles CLI command 'cli reload permissions' */
1073 static char *handle_cli_reload_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1074 {
1075  switch (cmd) {
1076  case CLI_INIT:
1077  e->command = "cli reload permissions";
1078  e->usage =
1079  "Usage: cli reload permissions\n"
1080  " Reload the 'cli_permissions.conf' file.\n";
1081  return NULL;
1082  case CLI_GENERATE:
1083  return NULL;
1084  }
1085 
1086  ast_cli_perms_init(1);
1087 
1088  return CLI_SUCCESS;
1089 }
1090 
1091 /*! \brief handles CLI command 'cli check permissions' */
1092 static char *handle_cli_check_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1093 {
1094  struct passwd *pw = NULL;
1095  struct group *gr;
1096  int gid = -1, uid = -1;
1097  char command[AST_MAX_ARGS] = "";
1098  struct ast_cli_entry *ce = NULL;
1099  int found = 0;
1100  char *group, *tmp;
1101 
1102  switch (cmd) {
1103  case CLI_INIT:
1104  e->command = "cli check permissions";
1105  e->usage =
1106  "Usage: cli check permissions {<username>|@<groupname>|<username>@<groupname>} [<command>]\n"
1107  " Check permissions config for a user@group or list the allowed commands for the specified user.\n"
1108  " The username or the groupname may be omitted.\n";
1109  return NULL;
1110  case CLI_GENERATE:
1111  if (a->pos >= 4) {
1112  return ast_cli_generator(a->line + strlen("cli check permissions") + strlen(a->argv[3]) + 1, a->word, a->n);
1113  }
1114  return NULL;
1115  }
1116 
1117  if (a->argc < 4) {
1118  return CLI_SHOWUSAGE;
1119  }
1120 
1121  tmp = ast_strdupa(a->argv[3]);
1122  group = strchr(tmp, '@');
1123  if (group) {
1124  gr = getgrnam(&group[1]);
1125  if (!gr) {
1126  ast_cli(a->fd, "Unknown group '%s'\n", &group[1]);
1127  return CLI_FAILURE;
1128  }
1129  group[0] = '\0';
1130  gid = gr->gr_gid;
1131  }
1132 
1133  if (!group && ast_strlen_zero(tmp)) {
1134  ast_cli(a->fd, "You didn't supply a username\n");
1135  } else if (!ast_strlen_zero(tmp) && !(pw = getpwnam(tmp))) {
1136  ast_cli(a->fd, "Unknown user '%s'\n", tmp);
1137  return CLI_FAILURE;
1138  } else if (pw) {
1139  uid = pw->pw_uid;
1140  }
1141 
1142  if (a->argc == 4) {
1143  while ((ce = cli_next(ce))) {
1144  /* Hide commands that start with '_' */
1145  if (ce->_full_cmd[0] == '_') {
1146  continue;
1147  }
1148  if (cli_has_permissions(uid, gid, ce->_full_cmd)) {
1149  ast_cli(a->fd, "%30.30s %s\n", ce->_full_cmd, S_OR(ce->summary, "<no description available>"));
1150  found++;
1151  }
1152  }
1153  if (!found) {
1154  ast_cli(a->fd, "You are not allowed to run any command on Asterisk\n");
1155  }
1156  } else {
1157  ast_join(command, sizeof(command), a->argv + 4);
1158  ast_cli(a->fd, "%s '%s%s%s' is %s to run command: '%s'\n", uid >= 0 ? "User" : "Group", tmp,
1159  group && uid >= 0 ? "@" : "",
1160  group ? &group[1] : "",
1161  cli_has_permissions(uid, gid, command) ? "allowed" : "not allowed", command);
1162  }
1163 
1164  return CLI_SUCCESS;
1165 }
1166 
1167 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock);
1168 
1169 static char *handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1170 {
1171  char *buf, *obuf;
1172  int buflen = 2048;
1173  int len = 0;
1174  char **matches;
1175  int x, matchlen;
1176 
1177  switch (cmd) {
1178  case CLI_INIT:
1179  e->command = "_command matchesarray";
1180  e->usage =
1181  "Usage: _command matchesarray \"<line>\" text \n"
1182  " This function is used internally to help with command completion and should.\n"
1183  " never be called by the user directly.\n";
1184  return NULL;
1185  case CLI_GENERATE:
1186  return NULL;
1187  }
1188 
1189  if (a->argc != 4)
1190  return CLI_SHOWUSAGE;
1191  if (!(buf = ast_malloc(buflen)))
1192  return CLI_FAILURE;
1193  buf[len] = '\0';
1194  matches = ast_cli_completion_matches(a->argv[2], a->argv[3]);
1195  if (matches) {
1196  for (x=0; matches[x]; x++) {
1197  matchlen = strlen(matches[x]) + 1;
1198  if (len + matchlen >= buflen) {
1199  buflen += matchlen * 3;
1200  obuf = buf;
1201  if (!(buf = ast_realloc(obuf, buflen)))
1202  /* Memory allocation failure... Just free old buffer and be done */
1203  ast_free(obuf);
1204  }
1205  if (buf)
1206  len += sprintf( buf + len, "%s ", matches[x]);
1207  ast_free(matches[x]);
1208  matches[x] = NULL;
1209  }
1210  ast_free(matches);
1211  }
1212 
1213  if (buf) {
1214  ast_cli(a->fd, "%s%s",buf, AST_CLI_COMPLETE_EOF);
1215  ast_free(buf);
1216  } else
1217  ast_cli(a->fd, "NULL\n");
1218 
1219  return CLI_SUCCESS;
1220 }
1221 
1222 
1223 
1224 static char *handle_commandnummatches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1225 {
1226  int matches = 0;
1227 
1228  switch (cmd) {
1229  case CLI_INIT:
1230  e->command = "_command nummatches";
1231  e->usage =
1232  "Usage: _command nummatches \"<line>\" text \n"
1233  " This function is used internally to help with command completion and should.\n"
1234  " never be called by the user directly.\n";
1235  return NULL;
1236  case CLI_GENERATE:
1237  return NULL;
1238  }
1239 
1240  if (a->argc != 4)
1241  return CLI_SHOWUSAGE;
1242 
1243  matches = ast_cli_generatornummatches(a->argv[2], a->argv[3]);
1244 
1245  ast_cli(a->fd, "%d", matches);
1246 
1247  return CLI_SUCCESS;
1248 }
1249 
1250 static char *handle_commandcomplete(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1251 {
1252  char *buf;
1253  switch (cmd) {
1254  case CLI_INIT:
1255  e->command = "_command complete";
1256  e->usage =
1257  "Usage: _command complete \"<line>\" text state\n"
1258  " This function is used internally to help with command completion and should.\n"
1259  " never be called by the user directly.\n";
1260  return NULL;
1261  case CLI_GENERATE:
1262  return NULL;
1263  }
1264  if (a->argc != 5)
1265  return CLI_SHOWUSAGE;
1266  buf = __ast_cli_generator(a->argv[2], a->argv[3], atoi(a->argv[4]), 0);
1267  if (buf) {
1268  ast_cli(a->fd, "%s", buf);
1269  ast_free(buf);
1270  } else
1271  ast_cli(a->fd, "NULL\n");
1272  return CLI_SUCCESS;
1273 }
1274 
1276  int fd;
1277  int is_off;
1278 };
1279 
1280 static int channel_set_debug(void *obj, void *arg, void *data, int flags)
1281 {
1282  struct ast_channel *chan = obj;
1283  struct channel_set_debug_args *args = data;
1284 
1285  ast_channel_lock(chan);
1286 
1287  if (!(chan->fin & DEBUGCHAN_FLAG) || !(chan->fout & DEBUGCHAN_FLAG)) {
1288  if (args->is_off) {
1289  chan->fin &= ~DEBUGCHAN_FLAG;
1290  chan->fout &= ~DEBUGCHAN_FLAG;
1291  } else {
1292  chan->fin |= DEBUGCHAN_FLAG;
1293  chan->fout |= DEBUGCHAN_FLAG;
1294  }
1295  ast_cli(args->fd, "Debugging %s on channel %s\n", args->is_off ? "disabled" : "enabled",
1296  chan->name);
1297  }
1298 
1299  ast_channel_unlock(chan);
1300 
1301  return 0;
1302 }
1303 
1304 static char *handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1305 {
1306  struct ast_channel *c = NULL;
1307  struct channel_set_debug_args args = {
1308  .fd = a->fd,
1309  };
1310 
1311  switch (cmd) {
1312  case CLI_INIT:
1313  e->command = "core set debug channel";
1314  e->usage =
1315  "Usage: core set debug channel <all|channel> [off]\n"
1316  " Enables/disables debugging on all or on a specific channel.\n";
1317  return NULL;
1318  case CLI_GENERATE:
1319  /* XXX remember to handle the optional "off" */
1320  if (a->pos != e->args)
1321  return NULL;
1322  return a->n == 0 ? ast_strdup("all") : ast_complete_channels(a->line, a->word, a->pos, a->n - 1, e->args);
1323  }
1324 
1325  if (cmd == (CLI_HANDLER + 1000)) {
1326  /* called from handle_nodebugchan_deprecated */
1327  args.is_off = 1;
1328  } else if (a->argc == e->args + 2) {
1329  /* 'core set debug channel {all|chan_id}' */
1330  if (!strcasecmp(a->argv[e->args + 1], "off"))
1331  args.is_off = 1;
1332  else
1333  return CLI_SHOWUSAGE;
1334  } else if (a->argc != e->args + 1) {
1335  return CLI_SHOWUSAGE;
1336  }
1337 
1338  if (!strcasecmp("all", a->argv[e->args])) {
1339  if (args.is_off) {
1342  } else {
1345  }
1347  } else {
1348  if ((c = ast_channel_get_by_name(a->argv[e->args]))) {
1349  channel_set_debug(c, NULL, &args, 0);
1350  ast_channel_unref(c);
1351  } else {
1352  ast_cli(a->fd, "No such channel %s\n", a->argv[e->args]);
1353  }
1354  }
1355 
1356  ast_cli(a->fd, "Debugging on new channels is %s\n", args.is_off ? "disabled" : "enabled");
1357 
1358  return CLI_SUCCESS;
1359 }
1360 
1361 static char *handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1362 {
1363  char *res;
1364 
1365  switch (cmd) {
1366  case CLI_INIT:
1367  e->command = "no debug channel";
1368  return NULL;
1369  case CLI_HANDLER:
1370  /* exit out of switch statement */
1371  break;
1372  default:
1373  return NULL;
1374  }
1375 
1376  if (a->argc != e->args + 1)
1377  return CLI_SHOWUSAGE;
1378 
1379  /* add a 'magic' value to the CLI_HANDLER command so that
1380  * handle_core_set_debug_channel() will act as if 'off'
1381  * had been specified as part of the command
1382  */
1383  res = handle_core_set_debug_channel(e, CLI_HANDLER + 1000, a);
1384 
1385  return res;
1386 }
1387 
1388 static char *handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1389 {
1390  struct ast_channel *c=NULL;
1391  struct timeval now;
1392  char cdrtime[256];
1393  char nf[256], wf[256], rf[256];
1394  struct ast_str *write_transpath = ast_str_alloca(256);
1395  struct ast_str *read_transpath = ast_str_alloca(256);
1396  struct ast_str *obuf;/*!< Buffer for variable, CDR variable, and trace output. */
1397  struct ast_str *output;/*!< Accumulation buffer for all output. */
1398  long elapsed_seconds=0;
1399  int hour=0, min=0, sec=0;
1400 #ifdef CHANNEL_TRACE
1401  int trace_enabled;
1402 #endif
1403 
1404  switch (cmd) {
1405  case CLI_INIT:
1406  e->command = "core show channel";
1407  e->usage =
1408  "Usage: core show channel <channel>\n"
1409  " Shows lots of information about the specified channel.\n";
1410  return NULL;
1411  case CLI_GENERATE:
1412  return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
1413  }
1414 
1415  if (a->argc != 4) {
1416  return CLI_SHOWUSAGE;
1417  }
1418 
1419  now = ast_tvnow();
1420 
1421  if (!(c = ast_channel_get_by_name(a->argv[3]))) {
1422  ast_cli(a->fd, "%s is not a known channel\n", a->argv[3]);
1423  return CLI_SUCCESS;
1424  }
1425 
1426  obuf = ast_str_thread_get(&ast_str_thread_global_buf, 16);
1427  if (!obuf) {
1428  return CLI_FAILURE;
1429  }
1430  output = ast_str_create(8192);
1431  if (!output) {
1432  return CLI_FAILURE;
1433  }
1434 
1435  ast_channel_lock(c);
1436 
1437  if (c->cdr) {
1438  elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec;
1439  hour = elapsed_seconds / 3600;
1440  min = (elapsed_seconds % 3600) / 60;
1441  sec = elapsed_seconds % 60;
1442  snprintf(cdrtime, sizeof(cdrtime), "%dh%dm%ds", hour, min, sec);
1443  } else {
1444  strcpy(cdrtime, "N/A");
1445  }
1446 
1447  ast_str_append(&output, 0,
1448  " -- General --\n"
1449  " Name: %s\n"
1450  " Type: %s\n"
1451  " UniqueID: %s\n"
1452  " LinkedID: %s\n"
1453  " Caller ID: %s\n"
1454  " Caller ID Name: %s\n"
1455  "Connected Line ID: %s\n"
1456  "Connected Line ID Name: %s\n"
1457  " DNID Digits: %s\n"
1458  " Language: %s\n"
1459  " State: %s (%u)\n"
1460  " Rings: %d\n"
1461  " NativeFormats: %s\n"
1462  " WriteFormat: %s\n"
1463  " ReadFormat: %s\n"
1464  " WriteTranscode: %s %s\n"
1465  " ReadTranscode: %s %s\n"
1466  "1st File Descriptor: %d\n"
1467  " Frames in: %u%s\n"
1468  " Frames out: %u%s\n"
1469  " Time to Hangup: %ld\n"
1470  " Elapsed Time: %s\n"
1471  " Direct Bridge: %s\n"
1472  "Indirect Bridge: %s\n"
1473  " -- PBX --\n"
1474  " Context: %s\n"
1475  " Extension: %s\n"
1476  " Priority: %d\n"
1477  " Call Group: %llu\n"
1478  " Pickup Group: %llu\n"
1479  " Application: %s\n"
1480  " Data: %s\n"
1481  " Blocking in: %s\n",
1482  c->name, c->tech->type, c->uniqueid, c->linkedid,
1483  S_COR(c->caller.id.number.valid, c->caller.id.number.str, "(N/A)"),
1484  S_COR(c->caller.id.name.valid, c->caller.id.name.str, "(N/A)"),
1485  S_COR(c->connected.id.number.valid, c->connected.id.number.str, "(N/A)"),
1486  S_COR(c->connected.id.name.valid, c->connected.id.name.str, "(N/A)"),
1487  S_OR(c->dialed.number.str, "(N/A)"),
1488  c->language,
1489  ast_state2str(c->_state), c->_state, c->rings,
1490  ast_getformatname_multiple(nf, sizeof(nf), c->nativeformats),
1491  ast_getformatname_multiple(wf, sizeof(wf), c->writeformat),
1492  ast_getformatname_multiple(rf, sizeof(rf), c->readformat),
1493  c->writetrans ? "Yes" : "No",
1494  ast_translate_path_to_str(c->writetrans, &write_transpath),
1495  c->readtrans ? "Yes" : "No",
1496  ast_translate_path_to_str(c->readtrans, &read_transpath),
1497  c->fds[0],
1498  c->fin & ~DEBUGCHAN_FLAG, (c->fin & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
1499  c->fout & ~DEBUGCHAN_FLAG, (c->fout & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
1500  (long)c->whentohangup.tv_sec,
1501  cdrtime, c->_bridge ? c->_bridge->name : "<none>", ast_bridged_channel(c) ? ast_bridged_channel(c)->name : "<none>",
1502  c->context, c->exten, c->priority, c->callgroup, c->pickupgroup, ( c->appl ? c->appl : "(N/A)" ),
1503  ( c-> data ? S_OR(c->data, "(Empty)") : "(None)"),
1504  (ast_test_flag(c, AST_FLAG_BLOCKING) ? c->blockproc : "(Not Blocking)"));
1505 
1506  if (pbx_builtin_serialize_variables(c, &obuf)) {
1507  ast_str_append(&output, 0, " Variables:\n%s\n", ast_str_buffer(obuf));
1508  }
1509 
1510  if (c->cdr && ast_cdr_serialize_variables(c->cdr, &obuf, '=', '\n', 1)) {
1511  ast_str_append(&output, 0, " CDR Variables:\n%s\n", ast_str_buffer(obuf));
1512  }
1513 
1514 #ifdef CHANNEL_TRACE
1515  trace_enabled = ast_channel_trace_is_enabled(c);
1516  ast_str_append(&output, 0, " Context Trace: %s\n",
1517  trace_enabled ? "Enabled" : "Disabled");
1518  if (trace_enabled && ast_channel_trace_serialize(c, &obuf)) {
1519  ast_str_append(&output, 0, " Trace:\n%s\n", ast_str_buffer(obuf));
1520  }
1521 #endif
1522 
1523  ast_channel_unlock(c);
1524  c = ast_channel_unref(c);
1525 
1526  ast_cli(a->fd, "%s", ast_str_buffer(output));
1527  ast_free(output);
1528  return CLI_SUCCESS;
1529 }
1530 
1531 /*
1532  * helper function to generate CLI matches from a fixed set of values.
1533  * A NULL word is acceptable.
1534  */
1535 char *ast_cli_complete(const char *word, const char * const choices[], int state)
1536 {
1537  int i, which = 0, len;
1538  len = ast_strlen_zero(word) ? 0 : strlen(word);
1539 
1540  for (i = 0; choices[i]; i++) {
1541  if ((!len || !strncasecmp(word, choices[i], len)) && ++which > state)
1542  return ast_strdup(choices[i]);
1543  }
1544  return NULL;
1545 }
1546 
1547 char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos)
1548 {
1549  struct ast_channel *c = NULL;
1550  int which = 0;
1551  char notfound = '\0';
1552  char *ret = &notfound; /* so NULL can break the loop */
1553  struct ast_channel_iterator *iter;
1554 
1555  if (pos != rpos) {
1556  return NULL;
1557  }
1558 
1559  if (ast_strlen_zero(word)) {
1561  } else {
1562  iter = ast_channel_iterator_by_name_new(word, strlen(word));
1563  }
1564 
1565  if (!iter) {
1566  return NULL;
1567  }
1568 
1569  while (ret == &notfound && (c = ast_channel_iterator_next(iter))) {
1570  if (++which > state) {
1571  ast_channel_lock(c);
1572  ret = ast_strdup(c->name);
1573  ast_channel_unlock(c);
1574  }
1575  ast_channel_unref(c);
1576  }
1577 
1579 
1580  return ret == &notfound ? NULL : ret;
1581 }
1582 
1583 static char *group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1584 {
1585 #define FORMAT_STRING "%-25s %-20s %-20s\n"
1586 
1587  struct ast_group_info *gi = NULL;
1588  int numchans = 0;
1589  regex_t regexbuf;
1590  int havepattern = 0;
1591 
1592  switch (cmd) {
1593  case CLI_INIT:
1594  e->command = "group show channels";
1595  e->usage =
1596  "Usage: group show channels [pattern]\n"
1597  " Lists all currently active channels with channel group(s) specified.\n"
1598  " Optional regular expression pattern is matched to group names for each\n"
1599  " channel.\n";
1600  return NULL;
1601  case CLI_GENERATE:
1602  return NULL;
1603  }
1604 
1605  if (a->argc < 3 || a->argc > 4)
1606  return CLI_SHOWUSAGE;
1607 
1608  if (a->argc == 4) {
1609  if (regcomp(&regexbuf, a->argv[3], REG_EXTENDED | REG_NOSUB))
1610  return CLI_SHOWUSAGE;
1611  havepattern = 1;
1612  }
1613 
1614  ast_cli(a->fd, FORMAT_STRING, "Channel", "Group", "Category");
1615 
1617 
1618  gi = ast_app_group_list_head();
1619  while (gi) {
1620  if (!havepattern || !regexec(&regexbuf, gi->group, 0, NULL, 0)) {
1621  ast_cli(a->fd, FORMAT_STRING, gi->chan->name, gi->group, (ast_strlen_zero(gi->category) ? "(default)" : gi->category));
1622  numchans++;
1623  }
1624  gi = AST_LIST_NEXT(gi, group_list);
1625  }
1626 
1628 
1629  if (havepattern)
1630  regfree(&regexbuf);
1631 
1632  ast_cli(a->fd, "%d active channel%s\n", numchans, ESS(numchans));
1633  return CLI_SUCCESS;
1634 #undef FORMAT_STRING
1635 }
1636 
1637 static char *handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1638 {
1639  switch (cmd) {
1640  case CLI_INIT:
1641  e->command = "core waitfullybooted";
1642  e->usage =
1643  "Usage: core waitfullybooted\n"
1644  " Wait until Asterisk has fully booted.\n";
1645  return NULL;
1646  case CLI_GENERATE:
1647  return NULL;
1648  }
1649 
1651  usleep(100);
1652  }
1653 
1654  ast_cli(a->fd, "Asterisk has fully booted.\n");
1655 
1656  return CLI_SUCCESS;
1657 }
1658 
1659 static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
1660 
1661 static struct ast_cli_entry cli_cli[] = {
1662  /* Deprecated, but preferred command is now consolidated (and already has a deprecated command for it). */
1663  AST_CLI_DEFINE(handle_commandcomplete, "Command complete"),
1664  AST_CLI_DEFINE(handle_commandnummatches, "Returns number of command matches"),
1665  AST_CLI_DEFINE(handle_commandmatchesarray, "Returns command matches array"),
1666 
1667  AST_CLI_DEFINE(handle_nodebugchan_deprecated, "Disable debugging on channel(s)"),
1668 
1669  AST_CLI_DEFINE(handle_chanlist, "Display information on channels"),
1670 
1671  AST_CLI_DEFINE(handle_showcalls, "Display information on calls"),
1672 
1673  AST_CLI_DEFINE(handle_showchan, "Display information on a specific channel"),
1674 
1675  AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
1676 
1677  AST_CLI_DEFINE(handle_verbose, "Set level of debug/verbose chattiness"),
1678 
1679  AST_CLI_DEFINE(group_show_channels, "Display active channels with group(s)"),
1680 
1681  AST_CLI_DEFINE(handle_help, "Display help list, or specific help on a command"),
1682 
1683  AST_CLI_DEFINE(handle_logger_mute, "Toggle logging output to a console"),
1684 
1685  AST_CLI_DEFINE(handle_modlist, "List modules and info"),
1686 
1687  AST_CLI_DEFINE(handle_load, "Load a module by name"),
1688 
1689  AST_CLI_DEFINE(handle_reload, "Reload configuration for a module"),
1690 
1691  AST_CLI_DEFINE(handle_core_reload, "Global reload"),
1692 
1693  AST_CLI_DEFINE(handle_unload, "Unload a module by name"),
1694 
1695  AST_CLI_DEFINE(handle_showuptime, "Show uptime information"),
1696 
1697  AST_CLI_DEFINE(handle_softhangup, "Request a hangup on a given channel"),
1698 
1699  AST_CLI_DEFINE(handle_cli_reload_permissions, "Reload CLI permissions config"),
1700 
1701  AST_CLI_DEFINE(handle_cli_show_permissions, "Show CLI permissions"),
1702 
1703  AST_CLI_DEFINE(handle_cli_check_permissions, "Try a permissions config for a user"),
1704 
1705  AST_CLI_DEFINE(handle_cli_wait_fullybooted, "Wait for Asterisk to be fully booted"),
1706 };
1707 
1708 /*!
1709  * Some regexp characters in cli arguments are reserved and used as separators.
1710  */
1711 static const char cli_rsvd[] = "[]{}|*%";
1712 
1713 /*!
1714  * initialize the _full_cmd string and related parameters,
1715  * return 0 on success, -1 on error.
1716  */
1717 static int set_full_cmd(struct ast_cli_entry *e)
1718 {
1719  int i;
1720  char buf[80];
1721 
1722  ast_join(buf, sizeof(buf), e->cmda);
1723  e->_full_cmd = ast_strdup(buf);
1724  if (!e->_full_cmd) {
1725  ast_log(LOG_WARNING, "-- cannot allocate <%s>\n", buf);
1726  return -1;
1727  }
1728  e->cmdlen = strcspn(e->_full_cmd, cli_rsvd);
1729  for (i = 0; e->cmda[i]; i++)
1730  ;
1731  e->args = i;
1732  return 0;
1733 }
1734 
1735 /*! \brief cleanup (free) cli_perms linkedlist. */
1736 static void destroy_user_perms(void)
1737 {
1738  struct cli_perm *perm;
1739  struct usergroup_cli_perm *user_perm;
1740 
1741  AST_RWLIST_WRLOCK(&cli_perms);
1742  while ((user_perm = AST_LIST_REMOVE_HEAD(&cli_perms, list))) {
1743  while ((perm = AST_LIST_REMOVE_HEAD(user_perm->perms, list))) {
1744  ast_free(perm->command);
1745  ast_free(perm);
1746  }
1747  ast_free(user_perm);
1748  }
1749  AST_RWLIST_UNLOCK(&cli_perms);
1750 }
1751 
1753 {
1754  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1755  struct ast_config *cfg;
1756  char *cat = NULL;
1757  struct ast_variable *v;
1758  struct usergroup_cli_perm *user_group, *cp_entry;
1759  struct cli_perm *perm = NULL;
1760  struct passwd *pw;
1761  struct group *gr;
1762 
1763  if (ast_mutex_trylock(&permsconfiglock)) {
1764  ast_log(LOG_NOTICE, "You must wait until last 'cli reload permissions' command finish\n");
1765  return 1;
1766  }
1767 
1768  cfg = ast_config_load2(perms_config, "" /* core, can't reload */, config_flags);
1769  if (!cfg) {
1770  ast_mutex_unlock(&permsconfiglock);
1771  return 1;
1772  } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1773  ast_mutex_unlock(&permsconfiglock);
1774  return 0;
1775  }
1776 
1777  /* free current structures. */
1779 
1780  while ((cat = ast_category_browse(cfg, cat))) {
1781  if (!strcasecmp(cat, "general")) {
1782  /* General options */
1783  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
1784  if (!strcasecmp(v->name, "default_perm")) {
1785  cli_default_perm = (!strcasecmp(v->value, "permit")) ? 1: 0;
1786  }
1787  }
1788  continue;
1789  }
1790 
1791  /* users or groups */
1792  gr = NULL, pw = NULL;
1793  if (cat[0] == '@') {
1794  /* This is a group */
1795  gr = getgrnam(&cat[1]);
1796  if (!gr) {
1797  ast_log (LOG_WARNING, "Unknown group '%s'\n", &cat[1]);
1798  continue;
1799  }
1800  } else {
1801  /* This is a user */
1802  pw = getpwnam(cat);
1803  if (!pw) {
1804  ast_log (LOG_WARNING, "Unknown user '%s'\n", cat);
1805  continue;
1806  }
1807  }
1808  user_group = NULL;
1809  /* Check for duplicates */
1810  AST_RWLIST_WRLOCK(&cli_perms);
1811  AST_LIST_TRAVERSE(&cli_perms, cp_entry, list) {
1812  if ((pw && cp_entry->uid == pw->pw_uid) || (gr && cp_entry->gid == gr->gr_gid)) {
1813  /* if it is duplicated, just added this new settings, to
1814  the current list. */
1815  user_group = cp_entry;
1816  break;
1817  }
1818  }
1819  AST_RWLIST_UNLOCK(&cli_perms);
1820 
1821  if (!user_group) {
1822  /* alloc space for the new user config. */
1823  user_group = ast_calloc(1, sizeof(*user_group));
1824  if (!user_group) {
1825  continue;
1826  }
1827  user_group->uid = (pw ? pw->pw_uid : -1);
1828  user_group->gid = (gr ? gr->gr_gid : -1);
1829  user_group->perms = ast_calloc(1, sizeof(*user_group->perms));
1830  if (!user_group->perms) {
1831  ast_free(user_group);
1832  continue;
1833  }
1834  }
1835  for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
1836  if (ast_strlen_zero(v->value)) {
1837  /* we need to check this condition cause it could break security. */
1838  ast_log(LOG_WARNING, "Empty permit/deny option in user '%s'\n", cat);
1839  continue;
1840  }
1841  if (!strcasecmp(v->name, "permit")) {
1842  perm = ast_calloc(1, sizeof(*perm));
1843  if (perm) {
1844  perm->permit = 1;
1845  perm->command = ast_strdup(v->value);
1846  }
1847  } else if (!strcasecmp(v->name, "deny")) {
1848  perm = ast_calloc(1, sizeof(*perm));
1849  if (perm) {
1850  perm->permit = 0;
1851  perm->command = ast_strdup(v->value);
1852  }
1853  } else {
1854  /* up to now, only 'permit' and 'deny' are possible values. */
1855  ast_log(LOG_WARNING, "Unknown '%s' option\n", v->name);
1856  continue;
1857  }
1858  if (perm) {
1859  /* Added the permission to the user's list. */
1860  AST_LIST_INSERT_TAIL(user_group->perms, perm, list);
1861  perm = NULL;
1862  }
1863  }
1864  AST_RWLIST_WRLOCK(&cli_perms);
1865  AST_RWLIST_INSERT_TAIL(&cli_perms, user_group, list);
1866  AST_RWLIST_UNLOCK(&cli_perms);
1867  }
1868 
1869  ast_config_destroy(cfg);
1870  ast_mutex_unlock(&permsconfiglock);
1871  return 0;
1872 }
1873 
1874 static void cli_shutdown(void)
1875 {
1876  ast_cli_unregister_multiple(cli_cli, ARRAY_LEN(cli_cli));
1877 }
1878 
1879 /*! \brief initialize the _full_cmd string in * each of the builtins. */
1881 {
1882  ast_cli_register_multiple(cli_cli, ARRAY_LEN(cli_cli));
1884 }
1885 
1886 /*!
1887  * match a word in the CLI entry.
1888  * returns -1 on mismatch, 0 on match of an optional word,
1889  * 1 on match of a full word.
1890  *
1891  * The pattern can be
1892  * any_word match for equal
1893  * [foo|bar|baz] optionally, one of these words
1894  * {foo|bar|baz} exactly, one of these words
1895  * % any word
1896  */
1897 static int word_match(const char *cmd, const char *cli_word)
1898 {
1899  int l;
1900  char *pos;
1901 
1902  if (ast_strlen_zero(cmd) || ast_strlen_zero(cli_word))
1903  return -1;
1904  if (!strchr(cli_rsvd, cli_word[0])) /* normal match */
1905  return (strcasecmp(cmd, cli_word) == 0) ? 1 : -1;
1906  l = strlen(cmd);
1907  /* wildcard match - will extend in the future */
1908  if (l > 0 && cli_word[0] == '%') {
1909  return 1; /* wildcard */
1910  }
1911 
1912  /* Start a search for the command entered against the cli word in question */
1913  pos = strcasestr(cli_word, cmd);
1914  while (pos) {
1915 
1916  /*
1917  *Check if the word matched with is surrounded by reserved characters on both sides
1918  * and isn't at the beginning of the cli_word since that would make it check in a location we shouldn't know about.
1919  * If it is surrounded by reserved chars and isn't at the beginning, it's a match.
1920  */
1921  if (pos != cli_word && strchr(cli_rsvd, pos[-1]) && strchr(cli_rsvd, pos[l])) {
1922  return 1; /* valid match */
1923  }
1924 
1925  /* Ok, that one didn't match, strcasestr to the next appearance of the command and start over.*/
1926  pos = strcasestr(pos + 1, cmd);
1927  }
1928  /* If no matches were found over the course of the while loop, we hit the end of the string. It's a mismatch. */
1929  return -1;
1930 }
1931 
1932 /*! \brief if word is a valid prefix for token, returns the pos-th
1933  * match as a malloced string, or NULL otherwise.
1934  * Always tell in *actual how many matches we got.
1935  */
1936 static char *is_prefix(const char *word, const char *token,
1937  int pos, int *actual)
1938 {
1939  int lw;
1940  char *s, *t1;
1941 
1942  *actual = 0;
1943  if (ast_strlen_zero(token))
1944  return NULL;
1945  if (ast_strlen_zero(word))
1946  word = ""; /* dummy */
1947  lw = strlen(word);
1948  if (strcspn(word, cli_rsvd) != lw)
1949  return NULL; /* no match if word has reserved chars */
1950  if (strchr(cli_rsvd, token[0]) == NULL) { /* regular match */
1951  if (strncasecmp(token, word, lw)) /* no match */
1952  return NULL;
1953  *actual = 1;
1954  return (pos != 0) ? NULL : ast_strdup(token);
1955  }
1956  /* now handle regexp match */
1957 
1958  /* Wildcard always matches, so we never do is_prefix on them */
1959 
1960  t1 = ast_strdupa(token + 1); /* copy, skipping first char */
1961  while (pos >= 0 && (s = strsep(&t1, cli_rsvd)) && *s) {
1962  if (*s == '%') /* wildcard */
1963  continue;
1964  if (strncasecmp(s, word, lw)) /* no match */
1965  continue;
1966  (*actual)++;
1967  if (pos-- == 0)
1968  return ast_strdup(s);
1969  }
1970  return NULL;
1971 }
1972 
1973 /*!
1974  * \internal
1975  * \brief locate a cli command in the 'helpers' list (which must be locked).
1976  * The search compares word by word taking care of regexps in e->cmda
1977  * This function will return NULL when nothing is matched, or the ast_cli_entry that matched.
1978  * \param cmds
1979  * \param match_type has 3 possible values:
1980  * 0 returns if the search key is equal or longer than the entry.
1981  * note that trailing optional arguments are skipped.
1982  * -1 true if the mismatch is on the last word XXX not true!
1983  * 1 true only on complete, exact match.
1984  *
1985  */
1986 static struct ast_cli_entry *find_cli(const char * const cmds[], int match_type)
1987 {
1988  int matchlen = -1; /* length of longest match so far */
1989  struct ast_cli_entry *cand = NULL, *e=NULL;
1990 
1991  while ( (e = cli_next(e)) ) {
1992  /* word-by word regexp comparison */
1993  const char * const *src = cmds;
1994  const char * const *dst = e->cmda;
1995  int n = 0;
1996  for (;; dst++, src += n) {
1997  n = word_match(*src, *dst);
1998  if (n < 0)
1999  break;
2000  }
2001  if (ast_strlen_zero(*dst) || ((*dst)[0] == '[' && ast_strlen_zero(dst[1]))) {
2002  /* no more words in 'e' */
2003  if (ast_strlen_zero(*src)) /* exact match, cannot do better */
2004  break;
2005  /* Here, cmds has more words than the entry 'e' */
2006  if (match_type != 0) /* but we look for almost exact match... */
2007  continue; /* so we skip this one. */
2008  /* otherwise we like it (case 0) */
2009  } else { /* still words in 'e' */
2010  if (ast_strlen_zero(*src))
2011  continue; /* cmds is shorter than 'e', not good */
2012  /* Here we have leftover words in cmds and 'e',
2013  * but there is a mismatch. We only accept this one if match_type == -1
2014  * and this is the last word for both.
2015  */
2016  if (match_type != -1 || !ast_strlen_zero(src[1]) ||
2017  !ast_strlen_zero(dst[1])) /* not the one we look for */
2018  continue;
2019  /* good, we are in case match_type == -1 and mismatch on last word */
2020  }
2021  if (src - cmds > matchlen) { /* remember the candidate */
2022  matchlen = src - cmds;
2023  cand = e;
2024  }
2025  }
2026 
2027  return e ? e : cand;
2028 }
2029 
2030 static char *find_best(const char *argv[])
2031 {
2032  static char cmdline[80];
2033  int x;
2034  /* See how close we get, then print the candidate */
2035  const char *myargv[AST_MAX_CMD_LEN] = { NULL, };
2036 
2038  for (x = 0; argv[x]; x++) {
2039  myargv[x] = argv[x];
2040  if (!find_cli(myargv, -1))
2041  break;
2042  }
2044  ast_join(cmdline, sizeof(cmdline), myargv);
2045  return cmdline;
2046 }
2047 
2048 static int cli_is_registered(struct ast_cli_entry *e)
2049 {
2050  struct ast_cli_entry *cur = NULL;
2051 
2052  while ((cur = cli_next(cur))) {
2053  if (cur == e) {
2054  return 1;
2055  }
2056  }
2057  return 0;
2058 }
2059 
2060 static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
2061 {
2062  if (e->inuse) {
2063  ast_log(LOG_WARNING, "Can't remove command that is in use\n");
2064  } else {
2066  AST_RWLIST_REMOVE(&helpers, e, list);
2068  ast_free(e->_full_cmd);
2069  e->_full_cmd = NULL;
2070  if (e->handler) {
2071  /* this is a new-style entry. Reset fields and free memory. */
2072  char *cmda = (char *) e->cmda;
2073  memset(cmda, '\0', sizeof(e->cmda));
2074  ast_free(e->command);
2075  e->command = NULL;
2076  e->usage = NULL;
2077  }
2078  }
2079  return 0;
2080 }
2081 
2082 static int __ast_cli_register(struct ast_cli_entry *e, struct ast_cli_entry *ed)
2083 {
2084  struct ast_cli_entry *cur;
2085  int i, lf, ret = -1;
2086 
2087  struct ast_cli_args a; /* fake argument */
2088  char **dst = (char **)e->cmda; /* need to cast as the entry is readonly */
2089  char *s;
2090 
2092 
2093  if (cli_is_registered(e)) {
2094  ast_log(LOG_WARNING, "Command '%s' already registered (the same ast_cli_entry)\n",
2095  S_OR(e->_full_cmd, e->command));
2096  ret = 0; /* report success */
2097  goto done;
2098  }
2099 
2100  memset(&a, '\0', sizeof(a));
2101  e->handler(e, CLI_INIT, &a);
2102  /* XXX check that usage and command are filled up */
2103  s = ast_skip_blanks(e->command);
2104  s = e->command = ast_strdup(s);
2105  for (i=0; !ast_strlen_zero(s) && i < AST_MAX_CMD_LEN-1; i++) {
2106  *dst++ = s; /* store string */
2107  s = ast_skip_nonblanks(s);
2108  if (*s == '\0') /* we are done */
2109  break;
2110  *s++ = '\0';
2111  s = ast_skip_blanks(s);
2112  }
2113  *dst++ = NULL;
2114 
2115  if (find_cli(e->cmda, 1)) {
2116  ast_log(LOG_WARNING, "Command '%s' already registered (or something close enough)\n",
2117  S_OR(e->_full_cmd, e->command));
2118  goto done;
2119  }
2120  if (set_full_cmd(e)) {
2121  ast_log(LOG_WARNING, "Error registering CLI Command '%s'\n",
2122  S_OR(e->_full_cmd, e->command));
2123  goto done;
2124  }
2125 
2126  lf = e->cmdlen;
2128  int len = cur->cmdlen;
2129  if (lf < len)
2130  len = lf;
2131  if (strncasecmp(e->_full_cmd, cur->_full_cmd, len) < 0) {
2133  break;
2134  }
2135  }
2137 
2138  if (!cur)
2139  AST_RWLIST_INSERT_TAIL(&helpers, e, list);
2140  ret = 0; /* success */
2141 
2142 done:
2144  if (ret) {
2145  ast_free(e->command);
2146  e->command = NULL;
2147  }
2148 
2149  return ret;
2150 }
2151 
2152 /* wrapper function, so we can unregister deprecated commands recursively */
2154 {
2155  return __ast_cli_unregister(e, NULL);
2156 }
2157 
2158 /* wrapper function, so we can register deprecated commands recursively */
2160 {
2161  return __ast_cli_register(e, NULL);
2162 }
2163 
2164 /*
2165  * register/unregister an array of entries.
2166  */
2168 {
2169  int i, res = 0;
2170 
2171  for (i = 0; i < len; i++)
2172  res |= ast_cli_register(e + i);
2173 
2174  return res;
2175 }
2176 
2178 {
2179  int i, res = 0;
2180 
2181  for (i = 0; i < len; i++)
2182  res |= ast_cli_unregister(e + i);
2183 
2184  return res;
2185 }
2186 
2187 
2188 /*! \brief helper for final part of handle_help
2189  * if locked = 1, assume the list is already locked
2190  */
2191 static char *help1(int fd, const char * const match[], int locked)
2192 {
2193  char matchstr[80] = "";
2194  struct ast_cli_entry *e = NULL;
2195  int len = 0;
2196  int found = 0;
2197 
2198  if (match) {
2199  ast_join(matchstr, sizeof(matchstr), match);
2200  len = strlen(matchstr);
2201  }
2202  if (!locked)
2204  while ( (e = cli_next(e)) ) {
2205  /* Hide commands that start with '_' */
2206  if (e->_full_cmd[0] == '_')
2207  continue;
2208  if (match && strncasecmp(matchstr, e->_full_cmd, len))
2209  continue;
2210  ast_cli(fd, "%30.30s %s\n", e->_full_cmd, S_OR(e->summary, "<no description available>"));
2211  found++;
2212  }
2213  if (!locked)
2215  if (!found && matchstr[0])
2216  ast_cli(fd, "No such command '%s'.\n", matchstr);
2217  return CLI_SUCCESS;
2218 }
2219 
2220 static char *handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2221 {
2222  char fullcmd[80];
2223  struct ast_cli_entry *my_e;
2224  char *res = CLI_SUCCESS;
2225 
2226  if (cmd == CLI_INIT) {
2227  e->command = "core show help";
2228  e->usage =
2229  "Usage: core show help [topic]\n"
2230  " When called with a topic as an argument, displays usage\n"
2231  " information on the given command. If called without a\n"
2232  " topic, it provides a list of commands.\n";
2233  return NULL;
2234 
2235  } else if (cmd == CLI_GENERATE) {
2236  /* skip first 14 or 15 chars, "core show help " */
2237  int l = strlen(a->line);
2238 
2239  if (l > 15) {
2240  l = 15;
2241  }
2242  /* XXX watch out, should stop to the non-generator parts */
2243  return __ast_cli_generator(a->line + l, a->word, a->n, 0);
2244  }
2245  if (a->argc == e->args) {
2246  return help1(a->fd, NULL, 0);
2247  }
2248 
2250  my_e = find_cli(a->argv + 3, 1); /* try exact match first */
2251  if (!my_e) {
2252  res = help1(a->fd, a->argv + 3, 1 /* locked */);
2254  return res;
2255  }
2256  if (my_e->usage)
2257  ast_cli(a->fd, "%s", my_e->usage);
2258  else {
2259  ast_join(fullcmd, sizeof(fullcmd), a->argv + 3);
2260  ast_cli(a->fd, "No help text available for '%s'.\n", fullcmd);
2261  }
2263  return res;
2264 }
2265 
2266 static char *parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
2267 {
2268  char *duplicate, *cur;
2269  int x = 0;
2270  int quoted = 0;
2271  int escaped = 0;
2272  int whitespace = 1;
2273  int dummy = 0;
2274 
2275  if (trailingwhitespace == NULL)
2276  trailingwhitespace = &dummy;
2277  *trailingwhitespace = 0;
2278  if (s == NULL) /* invalid, though! */
2279  return NULL;
2280  /* make a copy to store the parsed string */
2281  if (!(duplicate = ast_strdup(s)))
2282  return NULL;
2283 
2284  cur = duplicate;
2285 
2286  /* Remove leading spaces from the command */
2287  while (isspace(*s)) {
2288  cur++;
2289  s++;
2290  }
2291 
2292  /* scan the original string copying into cur when needed */
2293  for (; *s ; s++) {
2294  if (x >= max - 1) {
2295  ast_log(LOG_WARNING, "Too many arguments, truncating at %s\n", s);
2296  break;
2297  }
2298  if (*s == '"' && !escaped) {
2299  quoted = !quoted;
2300  if (quoted && whitespace) {
2301  /* start a quoted string from previous whitespace: new argument */
2302  argv[x++] = cur;
2303  whitespace = 0;
2304  }
2305  } else if ((*s == ' ' || *s == '\t') && !(quoted || escaped)) {
2306  /* If we are not already in whitespace, and not in a quoted string or
2307  processing an escape sequence, and just entered whitespace, then
2308  finalize the previous argument and remember that we are in whitespace
2309  */
2310  if (!whitespace) {
2311  *cur++ = '\0';
2312  whitespace = 1;
2313  }
2314  } else if (*s == '\\' && !escaped) {
2315  escaped = 1;
2316  } else {
2317  if (whitespace) {
2318  /* we leave whitespace, and are not quoted. So it's a new argument */
2319  argv[x++] = cur;
2320  whitespace = 0;
2321  }
2322  *cur++ = *s;
2323  escaped = 0;
2324  }
2325  }
2326  /* Null terminate */
2327  *cur++ = '\0';
2328  /* XXX put a NULL in the last argument, because some functions that take
2329  * the array may want a null-terminated array.
2330  * argc still reflects the number of non-NULL entries.
2331  */
2332  argv[x] = NULL;
2333  *argc = x;
2334  *trailingwhitespace = whitespace;
2335  return duplicate;
2336 }
2337 
2338 /*! \brief Return the number of unique matches for the generator */
2339 int ast_cli_generatornummatches(const char *text, const char *word)
2340 {
2341  int matches = 0, i = 0;
2342  char *buf = NULL, *oldbuf = NULL;
2343 
2344  while ((buf = ast_cli_generator(text, word, i++))) {
2345  if (!oldbuf || strcmp(buf,oldbuf))
2346  matches++;
2347  if (oldbuf)
2348  ast_free(oldbuf);
2349  oldbuf = buf;
2350  }
2351  if (oldbuf)
2352  ast_free(oldbuf);
2353  return matches;
2354 }
2355 
2356 static void destroy_match_list(char **match_list, int matches)
2357 {
2358  if (match_list) {
2359  int idx;
2360 
2361  for (idx = 1; idx < matches; ++idx) {
2362  ast_free(match_list[idx]);
2363  }
2364  ast_free(match_list);
2365  }
2366 }
2367 
2368 char **ast_cli_completion_matches(const char *text, const char *word)
2369 {
2370  char **match_list = NULL, *retstr, *prevstr;
2371  char **new_list;
2372  size_t match_list_len, max_equal, which, i;
2373  int matches = 0;
2374 
2375  /* leave entry 0 free for the longest common substring */
2376  match_list_len = 1;
2377  while ((retstr = ast_cli_generator(text, word, matches)) != NULL) {
2378  if (matches + 1 >= match_list_len) {
2379  match_list_len <<= 1;
2380  new_list = ast_realloc(match_list, match_list_len * sizeof(*match_list));
2381  if (!new_list) {
2382  destroy_match_list(match_list, matches);
2383  return NULL;
2384  }
2385  match_list = new_list;
2386  }
2387  match_list[++matches] = retstr;
2388  }
2389 
2390  if (!match_list) {
2391  return match_list; /* NULL */
2392  }
2393 
2394  /* Find the longest substring that is common to all results
2395  * (it is a candidate for completion), and store a copy in entry 0.
2396  */
2397  prevstr = match_list[1];
2398  max_equal = strlen(prevstr);
2399  for (which = 2; which <= matches; which++) {
2400  for (i = 0; i < max_equal && toupper(prevstr[i]) == toupper(match_list[which][i]); i++)
2401  continue;
2402  max_equal = i;
2403  }
2404 
2405  retstr = ast_malloc(max_equal + 1);
2406  if (!retstr) {
2407  destroy_match_list(match_list, matches);
2408  return NULL;
2409  }
2410  ast_copy_string(retstr, match_list[1], max_equal + 1);
2411  match_list[0] = retstr;
2412 
2413  /* ensure that the array is NULL terminated */
2414  if (matches + 1 >= match_list_len) {
2415  new_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(*match_list));
2416  if (!new_list) {
2417  ast_free(retstr);
2418  destroy_match_list(match_list, matches);
2419  return NULL;
2420  }
2421  match_list = new_list;
2422  }
2423  match_list[matches + 1] = NULL;
2424 
2425  return match_list;
2426 }
2427 
2428 /*! \brief returns true if there are more words to match */
2429 static int more_words (const char * const *dst)
2430 {
2431  int i;
2432  for (i = 0; dst[i]; i++) {
2433  if (dst[i][0] != '[')
2434  return -1;
2435  }
2436  return 0;
2437 }
2438 
2439 /*
2440  * generate the entry at position 'state'
2441  */
2442 static char *__ast_cli_generator(const char *text, const char *word, int state, int lock)
2443 {
2444  const char *argv[AST_MAX_ARGS];
2445  struct ast_cli_entry *e = NULL;
2446  int x = 0, argindex, matchlen;
2447  int matchnum=0;
2448  char *ret = NULL;
2449  char matchstr[80] = "";
2450  int tws = 0;
2451  /* Split the argument into an array of words */
2452  char *duplicate = parse_args(text, &x, argv, ARRAY_LEN(argv), &tws);
2453 
2454  if (!duplicate) /* malloc error */
2455  return NULL;
2456 
2457  /* Compute the index of the last argument (could be an empty string) */
2458  argindex = (!ast_strlen_zero(word) && x>0) ? x-1 : x;
2459 
2460  /* rebuild the command, ignore terminating white space and flatten space */
2461  ast_join(matchstr, sizeof(matchstr)-1, argv);
2462  matchlen = strlen(matchstr);
2463  if (tws) {
2464  strcat(matchstr, " "); /* XXX */
2465  if (matchlen)
2466  matchlen++;
2467  }
2468  if (lock)
2470  while ( (e = cli_next(e)) ) {
2471  /* XXX repeated code */
2472  int src = 0, dst = 0, n = 0;
2473 
2474  if (e->command[0] == '_')
2475  continue;
2476 
2477  /*
2478  * Try to match words, up to and excluding the last word, which
2479  * is either a blank or something that we want to extend.
2480  */
2481  for (;src < argindex; dst++, src += n) {
2482  n = word_match(argv[src], e->cmda[dst]);
2483  if (n < 0)
2484  break;
2485  }
2486 
2487  if (src != argindex && more_words(e->cmda + dst)) /* not a match */
2488  continue;
2489  ret = is_prefix(argv[src], e->cmda[dst], state - matchnum, &n);
2490  matchnum += n; /* this many matches here */
2491  if (ret) {
2492  /*
2493  * argv[src] is a valid prefix of the next word in this
2494  * command. If this is also the correct entry, return it.
2495  */
2496  if (matchnum > state)
2497  break;
2498  ast_free(ret);
2499  ret = NULL;
2500  } else if (ast_strlen_zero(e->cmda[dst])) {
2501  /*
2502  * This entry is a prefix of the command string entered
2503  * (only one entry in the list should have this property).
2504  * Run the generator if one is available. In any case we are done.
2505  */
2506  if (e->handler) { /* new style command */
2507  struct ast_cli_args a = {
2508  .line = matchstr, .word = word,
2509  .pos = argindex,
2510  .n = state - matchnum,
2511  .argv = argv,
2512  .argc = x};
2513  ret = e->handler(e, CLI_GENERATE, &a);
2514  }
2515  if (ret)
2516  break;
2517  }
2518  }
2519  if (lock)
2521  ast_free(duplicate);
2522  return ret;
2523 }
2524 
2525 char *ast_cli_generator(const char *text, const char *word, int state)
2526 {
2527  return __ast_cli_generator(text, word, state, 1);
2528 }
2529 
2530 int ast_cli_command_full(int uid, int gid, int fd, const char *s)
2531 {
2532  const char *args[AST_MAX_ARGS + 1];
2533  struct ast_cli_entry *e;
2534  int x;
2535  char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL);
2536  char tmp[AST_MAX_ARGS + 1];
2537  char *retval = NULL;
2538  struct ast_cli_args a = {
2539  .fd = fd, .argc = x, .argv = args+1 };
2540 
2541  if (duplicate == NULL)
2542  return -1;
2543 
2544  if (x < 1) /* We need at least one entry, otherwise ignore */
2545  goto done;
2546 
2548  e = find_cli(args + 1, 0);
2549  if (e)
2552  if (e == NULL) {
2553  ast_cli(fd, "No such command '%s' (type 'core show help %s' for other possible commands)\n", s, find_best(args + 1));
2554  goto done;
2555  }
2556 
2557  ast_join(tmp, sizeof(tmp), args + 1);
2558  /* Check if the user has rights to run this command. */
2559  if (!cli_has_permissions(uid, gid, tmp)) {
2560  ast_cli(fd, "You don't have permissions to run '%s' command\n", tmp);
2561  ast_free(duplicate);
2562  return 0;
2563  }
2564 
2565  /*
2566  * Within the handler, argv[-1] contains a pointer to the ast_cli_entry.
2567  * Remember that the array returned by parse_args is NULL-terminated.
2568  */
2569  args[0] = (char *)e;
2570 
2571  retval = e->handler(e, CLI_HANDLER, &a);
2572 
2573  if (retval == CLI_SHOWUSAGE) {
2574  ast_cli(fd, "%s", S_OR(e->usage, "Invalid usage, but no usage information available.\n"));
2575  } else {
2576  if (retval == CLI_FAILURE)
2577  ast_cli(fd, "Command '%s' failed.\n", s);
2578  }
2579  ast_atomic_fetchadd_int(&e->inuse, -1);
2580 done:
2581  ast_free(duplicate);
2582  return 0;
2583 }
2584 
2585 int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s)
2586 {
2587  char cmd[512];
2588  int x, y = 0, count = 0;
2589 
2590  for (x = 0; x < size; x++) {
2591  cmd[y] = s[x];
2592  y++;
2593  if (s[x] == '\0') {
2594  ast_cli_command_full(uid, gid, fd, cmd);
2595  y = 0;
2596  count++;
2597  }
2598  }
2599  return count;
2600 }
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:81
void ast_std_free(void *ptr)
#define ast_channel_lock(chan)
Definition: channel.h:2466
static char * handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:389
Main Channel structure associated with a channel.
Definition: channel.h:742
channel group info
Definition: channel.h:2459
char * _full_cmd
Definition: cli.h:175
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
char ** ast_cli_completion_matches(const char *, const char *)
Generates a NULL-terminated array of strings that 1) begin with the string in the second parameter...
Definition: cli.c:2368
struct ast_party_connected_line connected
Channel Connected Line ID information.
Definition: channel.h:811
const char *const type
Definition: channel.h:508
#define NEEDCOMMA(x)
Asterisk locking-related definitions:
static struct ast_cli_entry cli_cli[]
Definition: cli.c:1661
struct ast_channel * ast_channel_iterator_next(struct ast_channel_iterator *i)
Get the next channel for a channel iterator.
Definition: channel.c:1715
Asterisk main include file. File version handling, generic pbx functions.
int rings
Definition: channel.h:840
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
#define VERBOSE_FORMAT_STRING
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
char * str
Subscriber phone number (Malloced)
Definition: channel.h:336
int ast_active_calls(void)
Retrieve the number of active calls.
Definition: pbx.c:5931
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
char * strsep(char **str, const char *delims)
#define AST_CLI_COMPLETE_EOF
Definition: cli.h:51
enum ast_module_load_result ast_load_resource(const char *resource_name)
Load a module.
Definition: loader.c:947
int priority
Definition: channel.h:841
#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:332
int cmdlen
Definition: cli.h:176
const ast_string_field uniqueid
Definition: channel.h:787
static char * group_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:1583
#define DEBUGCHAN_FLAG
Definition: channel.h:648
void ast_builtins_init(void)
initialize the _full_cmd string in * each of the builtins.
Definition: cli.c:1880
int ast_cli_register(struct ast_cli_entry *e)
Registers a command or an array of commands.
Definition: cli.c:2159
#define ast_strdup(a)
Definition: astmm.h:109
format_t writeformat
Definition: channel.h:854
static int cli_default_perm
Default permissions value 1=Permit 0=Deny.
Definition: cli.c:76
struct ast_party_id id
Connected party ID.
Definition: channel.h:403
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:2502
unsigned int level
Definition: cli.c:88
static char * find_best(const char *argv[])
Definition: cli.c:2030
#define ast_test_flag(p, flag)
Definition: utils.h:63
static char * handle_showuptime(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:721
int option_debug
Definition: asterisk.c:182
Support for translation of data formats. translate.c.
#define MINUTE
struct ast_party_name name
Subscriber name.
Definition: channel.h:290
const char * ast_config_AST_MODULE_DIR
Definition: asterisk.c:258
unsigned int ast_verbose_get_by_module(const char *module)
Get the verbose level for a module.
Definition: cli.c:140
int ast_carefulwrite(int fd, char *s, int len, int timeoutms)
Try to write string, but wait no more than ms milliseconds before timing out.
Definition: utils.c:1328
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
#define ast_set_flag(p, flag)
Definition: utils.h:70
int ast_cli_unregister(struct ast_cli_entry *e)
Unregisters a command or an array of commands.
Definition: cli.c:2153
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
static char * handle_softhangup(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:980
unsigned int fout
Definition: channel.h:847
const char * blockproc
Definition: channel.h:753
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
static char * complete_number(const char *partial, unsigned int min, unsigned int max, int n)
Definition: cli.c:349
static void dummy(char *unused,...)
Definition: chan_unistim.c:188
char * ast_complete_source_filename(const char *partial, int n)
Definition: asterisk.c:357
static ast_mutex_t climodentrylock
Definition: cli.c:648
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
#define AST_RWLIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_RWLIST_HEAD.
Definition: linkedlists.h:242
static int cli_has_permissions(int uid, int gid, const char *command)
Definition: cli.c:170
static char * parse_args(const char *s, int *argc, const char *argv[], int max, int *trailingwhitespace)
Definition: cli.c:2266
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
static int cli_is_registered(struct ast_cli_entry *e)
Definition: cli.c:2048
unsigned long global_fin
Definition: channel.c:104
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:792
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:100
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
Definition: cli.h:146
int option_verbose
Definition: asterisk.c:181
char * str
Subscriber name (Malloced)
Definition: channel.h:214
unsigned long global_fout
Definition: channel.c:104
static struct module_level_list debug_modules
Definition: cli.c:96
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:900
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
#define ast_mutex_lock(a)
Definition: lock.h:155
struct ast_cdr * cdr
Definition: channel.h:766
char * text
Definition: app_queue.c:1091
format_t nativeformats
Definition: channel.h:852
#define ast_str_alloca(init_len)
Definition: strings.h:608
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
map a debug or verbose level to a module name
Definition: cli.c:87
const char * ast_state2str(enum ast_channel_state)
Gives the string form of a given channel state.
Definition: channel.c:1007
static int more_words(const char *const *dst)
returns true if there are more words to match
Definition: cli.c:2429
const char * data
Definition: channel.h:755
static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
Definition: cli.c:2060
Definitions to aid in the use of thread local storage.
static int __ast_cli_register(struct ast_cli_entry *e, struct ast_cli_entry *ed)
Definition: cli.c:2082
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
const ast_string_field linkedid
Definition: channel.h:787
static int channel_set_debug(void *obj, void *arg, void *data, int flags)
Definition: cli.c:1280
struct cli_perm * next
Definition: cli.c:61
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: config.c:2499
ast_group_t pickupgroup
Definition: channel.h:819
Definition: ael.tab.c:203
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
char * ast_skip_nonblanks(const char *str)
Gets a pointer to first whitespace character in a string.
Definition: strings.h:136
const char * appl
Definition: channel.h:754
struct cli_perm::@239 list
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
const char * line
Definition: cli.h:156
ast_group_t callgroup
Definition: channel.h:818
void ast_console_toggle_mute(int fd, int silent)
mute or unmute a console from logging
Definition: asterisk.c:1159
#define HOUR
Utility functions.
int args
This gets set in ast_cli_register()
Definition: cli.h:179
static char * handle_chanlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:846
#define VERBOSE_FORMAT_STRING2
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, or NULL otherwise. Always tell in *actual how many matches we got.
Definition: cli.c:1936
char * ast_cli_complete(const char *word, const char *const choices[], int pos)
Definition: cli.c:1535
#define MODLIST_FORMAT
Definition: cli.c:645
#define WEEK
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
static int word_match(const char *cmd, const char *cli_word)
Definition: cli.c:1897
int inuse
Definition: cli.h:173
static char * handle_unload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:596
#define DAY
const char * value
Definition: config.h:79
static const char cli_rsvd[]
Definition: cli.c:1711
General Asterisk PBX channel definitions.
struct ast_party_dialed::@155 number
Dialed/Called number.
#define FORMAT_STRING
Asterisk file paths, configured in asterisk.conf.
#define CLI_NO_PERMS
Definition: cli.h:37
#define ast_mutex_trylock(a)
Definition: lock.h:157
#define AST_CLI_INITLEN
Initial buffer size for resulting strings in ast_cli()
Definition: cli.c:103
const int fd
Definition: cli.h:153
#define CONCISE_FORMAT_STRING
char * ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, int needsreload)
Match modules names for the Asterisk cli.
Definition: loader.c:626
struct cli_perm_head * perms
Definition: cli.c:70
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
const int n
Definition: cli.h:159
ast_mutex_t lock
Definition: app_meetme.c:964
static ast_mutex_t permsconfiglock
mutex used to prevent a user from running the &#39;cli reload permissions&#39; command while it is already ru...
Definition: cli.c:80
static struct module_level * find_module_level(const char *module, unsigned int debug)
Find the debug or verbose file setting.
Definition: cli.c:336
static const char perms_config[]
CLI permissions config file.
Definition: cli.c:74
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#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:83
int ast_softhangup(struct ast_channel *chan, int reason)
Softly hangup up a channel.
Definition: channel.c:2746
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
struct timeval ast_lastreloadtime
Definition: asterisk.c:219
static struct ast_cli_entry * find_cli(const char *const cmds[], int match_type)
Definition: cli.c:1986
static char * __ast_cli_generator(const char *text, const char *word, int state, int lock)
Definition: cli.c:2442
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: cli.c:2530
A set of macros to manage forward-linked lists.
const char * name
Definition: config.h:77
struct ast_channel * _bridge
Definition: channel.h:748
#define AST_RWLIST_INSERT_BEFORE_CURRENT
Definition: linkedlists.h:595
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
char * group
Definition: channel.h:2462
Core PBX routines and definitions.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:542
struct ast_channel * chan
Definition: channel.h:2460
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:1634
List of restrictions per user.
Definition: cli.c:58
const char *const * argv
Definition: cli.h:155
static void print_uptimestr(int fd, struct timeval timeval, const char *prefix, int printsec)
Definition: cli.c:661
int fds[AST_MAX_FDS]
Definition: channel.h:829
struct ast_party_dialed dialed
Dialed/Called information.
Definition: channel.h:797
struct ast_trans_pvt * writetrans
Definition: channel.h:762
struct ast_group_info * ast_app_group_list_head(void)
Get the head of the group count list.
Definition: app.c:1375
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
static int reload(void)
Definition: app_amd.c:497
static char * handle_core_set_debug_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:1304
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define AST_RWLIST_EMPTY
Definition: linkedlists.h:451
int ast_cdr_serialize_variables(struct ast_cdr *cdr, struct ast_str **buf, char delim, char sep, int recur)
Definition: cdr.c:409
int ast_processed_calls(void)
Retrieve the total number of calls processed through the PBX since last restart.
Definition: pbx.c:5936
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
list of users to apply restrictions.
Definition: cli.c:67
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
char *(* handler)(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.h:181
static int modlist_modentry(const char *module, const char *description, int usecnt, const char *like)
Definition: cli.c:651
unsigned int fin
Definition: channel.h:845
static struct @350 args
#define CLI_SHOWUSAGE
Definition: cli.h:44
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
enum ast_channel_state _state
Definition: channel.h:839
struct ast_channel * ast_bridged_channel(struct ast_channel *chan)
Find bridged channel.
Definition: channel.c:7160
#define FORMAT_STRING2
int ast_unload_resource(const char *resource_name, enum ast_module_unload_mode)
Unload a module.
Definition: loader.c:551
const ast_string_field name
Definition: channel.h:787
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:97
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static struct ast_cli_entry * cli_next(struct ast_cli_entry *e)
Definition: cli.c:712
#define LOG_NOTICE
Definition: logger.h:133
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: cli.c:2191
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
#define ast_channel_unlock(chan)
Definition: channel.h:2467
struct timeval start
Definition: cdr.h:100
#define CLI_FAILURE
Definition: cli.h:45
#define ESS(x)
Definition: cli.h:58
static const char name[]
int ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:721
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
static char * complete_fn(const char *word, int state)
Definition: cli.c:227
#define AST_MAX_ARGS
Definition: cli.h:49
#define YEAR
void ast_join(char *s, size_t len, const char *const w[])
Definition: utils.c:1690
const char * word
Definition: cli.h:157
static void cli_shutdown(void)
Definition: cli.c:1874
#define AST_RWLIST_REMOVE_HEAD
Definition: linkedlists.h:829
static char * handle_cli_reload_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handles CLI command &#39;cli reload permissions&#39;
Definition: cli.c:1073
char * category
Definition: channel.h:2461
static char * handle_cli_show_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handles CLI command &#39;cli show permissions&#39;
Definition: cli.c:1028
char * ast_cli_generator(const char *, const char *, int)
Readline madness Useful for readline, that&#39;s about it.
Definition: cli.c:2525
Structure used to handle boolean flags.
Definition: utils.h:200
struct ast_channel_iterator * ast_channel_iterator_by_name_new(const char *name, size_t name_len)
Create a new channel iterator based on name.
Definition: channel.c:1696
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:414
static char * handle_showchan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:1388
static char * handle_nodebugchan_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:1361
const char * usage
Definition: cli.h:171
static char * handle_showcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:791
static char * handle_commandmatchesarray(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:1169
struct timeval ast_startuptime
Definition: asterisk.c:218
#define CLI_SUCCESS
Definition: cli.h:43
int ast_app_group_list_unlock(void)
Unlock the group count list.
Definition: app.c:1380
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
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: cli.c:2585
#define AST_RWLIST_INSERT_TAIL
Definition: linkedlists.h:726
static void destroy_match_list(char **match_list, int matches)
Definition: cli.c:2356
struct ast_flags ast_options
Definition: asterisk.c:178
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:630
const char *const summary
Definition: cli.h:170
Standard Command Line Interface.
format_t readformat
Definition: channel.h:853
static int climodentryfd
Definition: cli.c:649
int ast_update_module_list(int(*modentry)(const char *module, const char *description, int usecnt, const char *like), const char *like)
Ask for a list of modules, descriptions, and use counts.
Definition: loader.c:1234
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
struct ast_group_info::@157 group_list
static void destroy_user_perms(void)
cleanup (free) cli_perms linkedlist.
Definition: cli.c:1736
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
const int pos
Definition: cli.h:158
#define ast_realloc(a, b)
Definition: astmm.h:103
static char * handle_cli_check_permissions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
handles CLI command &#39;cli check permissions&#39;
Definition: cli.c:1092
struct ast_channel_iterator * ast_channel_iterator_destroy(struct ast_channel_iterator *i)
Destroy a channel iterator.
Definition: channel.c:1649
#define MODLIST_FORMAT2
Definition: cli.c:646
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
char * ast_getformatname_multiple(char *buf, size_t size, format_t format)
Get the names of a set of formats.
Definition: frame.c:591
static char * handle_commandnummatches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:1224
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: cli.c:1547
static char * handle_commandcomplete(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:1250
List of users and permissions.
Definition: cli.c:82
Definition: cli.c:225
static char * handle_cli_wait_fullybooted(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:1637
char * command
Definition: cli.c:60
int ast_cli_generatornummatches(const char *, const char *)
Return the number of unique matches for the generator.
Definition: cli.c:2339
#define AST_RWLIST_REMOVE
Definition: linkedlists.h:870
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: utils.c:1601
struct timeval whentohangup
Definition: channel.h:789
struct ast_variable * next
Definition: config.h:82
static char * handle_logger_mute(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:571
static char * handle_modlist(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:752
static struct module_level_list verbose_modules
Definition: cli.c:98
struct ast_trans_pvt * readtrans
Definition: channel.h:763
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:669
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:229
struct ast_channel_iterator * ast_channel_iterator_all_new(void)
Create a new channel iterator.
Definition: channel.c:1701
unsigned int ast_debug_get_by_module(const char *module)
Get the debug level for a module.
Definition: cli.c:123
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1803
#define RESULT_SUCCESS
Definition: cli.h:39
static int set_full_cmd(struct ast_cli_entry *e)
Definition: cli.c:1717
const char *const cmda[AST_MAX_CMD_LEN]
Definition: cli.h:166
#define ast_malloc(a)
Definition: astmm.h:91
Asterisk module definitions.
char * strcasestr(const char *, const char *)
unsigned int permit
Definition: cli.c:59
int option_maxcalls
Definition: asterisk.c:184
struct ast_channel_tech * tech
Definition: channel.h:743
int ast_active_channels(void)
returns number of active/allocated channels
Definition: channel.c:848
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2069
static int usecnt
Definition: chan_unistim.c:236
int ast_app_group_list_rdlock(void)
Read Lock the group count list.
Definition: app.c:1370
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
#define AST_MAX_CMD_LEN
Definition: cli.h:47
static char * handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:310
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:602
const ast_string_field language
Definition: channel.h:787
static char * handle_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:2220
static struct ast_threadstorage ast_cli_buf
Definition: cli.c:100
static char * handle_load(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:249
char exten[AST_MAX_EXTENSION]
Definition: channel.h:869
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:526
int ast_cli_perms_init(int reload)
Definition: cli.c:1752
static char * handle_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: cli.c:275
#define AST_RWLIST_HEAD(name, type)
Defines a structure to be used to hold a read/write list of specified type.
Definition: linkedlists.h:198
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
#define ast_mutex_unlock(a)
Definition: lock.h:156
static uint16_t t1
Definition: res_pktccops.c:159
int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
Create a human-readable string, specifying all variables and their corresponding values.
Definition: pbx.c:10444
static char prefix[MAX_PREFIX]
Definition: http.c:107
static ast_group_t group
Definition: chan_agent.c:221
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292