summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.c190
-rw-r--r--main/cli.c359
-rw-r--r--main/logger.c210
-rw-r--r--main/manager.c8
-rw-r--r--main/pbx.c2
5 files changed, 550 insertions, 219 deletions
diff --git a/main/asterisk.c b/main/asterisk.c
index 86667e061..e2e01a51f 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -319,6 +319,9 @@ int daemon(int, int); /* defined in libresolv of all places */
struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
struct ast_flags ast_compat = { 0 };
+/*! Maximum active system verbosity level. */
+int ast_verb_sys_level;
+
int option_verbose; /*!< Verbosity level */
int option_debug; /*!< Debug level */
double ast_option_maxload; /*!< Max load avg on system */
@@ -347,6 +350,8 @@ struct console {
int uid; /*!< Remote user ID. */
int gid; /*!< Remote group ID. */
int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
+ /*! Verbosity level of this console. */
+ int option_verbose;
};
struct ast_atexit {
@@ -609,7 +614,8 @@ static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_c
ast_cli(a->fd, " Maximum open file handles: %d\n", ast_option_maxfiles);
else
ast_cli(a->fd, " Maximum open file handles: Not set\n");
- ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
+ ast_cli(a->fd, " Root console verbosity: %d\n", option_verbose);
+ ast_cli(a->fd, " Current console verbosity: %d\n", ast_verb_console_get());
ast_cli(a->fd, " Debug level: %d\n", option_debug);
ast_cli(a->fd, " Maximum load average: %lf\n", ast_option_maxload);
#if defined(HAVE_SYSINFO)
@@ -1331,29 +1337,33 @@ void ast_console_toggle_mute(int fd, int silent)
}
/*!
- * \brief log the string to all attached console clients
+ * \brief log the string to all attached network console clients
*/
static void ast_network_puts_mutable(const char *string, int level)
{
int x;
- for (x = 0;x < AST_MAX_CONNECTS; x++) {
- if (consoles[x].mute)
+
+ for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+ if (consoles[x].fd < 0
+ || consoles[x].mute
+ || consoles[x].levels[level]) {
continue;
- if (consoles[x].fd > -1) {
- if (!consoles[x].levels[level])
- fdprint(consoles[x].p[1], string);
}
+ fdprint(consoles[x].p[1], string);
}
}
/*!
- * \brief log the string to the console, and all attached
- * console clients
+ * \brief log the string to the root console, and all attached
+ * network console clients
*/
void ast_console_puts_mutable(const char *string, int level)
{
+ /* Send to the root console */
fputs(string, stdout);
fflush(stdout);
+
+ /* Send to any network console clients */
ast_network_puts_mutable(string, level);
}
@@ -1363,26 +1373,45 @@ void ast_console_puts_mutable(const char *string, int level)
static void ast_network_puts(const char *string)
{
int x;
- for (x = 0; x < AST_MAX_CONNECTS; x++) {
- if (consoles[x].fd > -1)
- fdprint(consoles[x].p[1], string);
+
+ for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+ if (consoles[x].fd < 0) {
+ continue;
+ }
+ fdprint(consoles[x].p[1], string);
}
}
/*!
- * \brief write the string to the console, and all attached
- * console clients
+ * \brief write the string to the root console, and all attached
+ * network console clients
*/
void ast_console_puts(const char *string)
{
+ /* Send to the root console */
fputs(string, stdout);
fflush(stdout);
+
+ /* Send to any network console clients */
ast_network_puts(string);
}
-static void network_verboser(const char *s)
+static void network_verboser(const char *string)
{
- ast_network_puts_mutable(s, __LOG_VERBOSE);
+ int x;
+ int verb_level;
+
+ /* Send to any network console clients if client verbocity allows. */
+ verb_level = VERBOSE_MAGIC2LEVEL(string);
+ for (x = 0; x < AST_MAX_CONNECTS; ++x) {
+ if (consoles[x].fd < 0
+ || consoles[x].mute
+ || consoles[x].levels[__LOG_VERBOSE]
+ || consoles[x].option_verbose < verb_level) {
+ continue;
+ }
+ fdprint(consoles[x].p[1], string);
+ }
}
static pthread_t lthread;
@@ -1446,6 +1475,7 @@ static int read_credentials(int fd, char *buffer, size_t size, struct console *c
return result;
}
+/* This is the thread running the remote console on the main process. */
static void *netconsole(void *vconsole)
{
struct console *con = vconsole;
@@ -1461,6 +1491,7 @@ static void *netconsole(void *vconsole)
ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
fdprint(con->fd, outbuf);
+ ast_verb_console_register(&con->option_verbose);
for (;;) {
fds[0].fd = con->fd;
fds[0].events = POLLIN;
@@ -1523,6 +1554,7 @@ static void *netconsole(void *vconsole)
break;
}
}
+ ast_verb_console_unregister();
if (!ast_opt_hide_connect) {
ast_verb(3, "Remote UNIX connection disconnected\n");
}
@@ -1575,24 +1607,25 @@ static void *listener(void *unused)
}
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
- consoles[x].fd = -1;
fdprint(s, "Server failed to create pipe\n");
close(s);
break;
}
flags = fcntl(consoles[x].p[1], F_GETFL);
fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
- consoles[x].fd = s;
consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
/* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
to know if the user didn't send the credentials. */
consoles[x].uid = -2;
consoles[x].gid = -2;
+ /* Server default of remote console verbosity level is OFF. */
+ consoles[x].option_verbose = 0;
+ consoles[x].fd = s;
if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
+ consoles[x].fd = -1;
ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
close(consoles[x].p[0]);
close(consoles[x].p[1]);
- consoles[x].fd = -1;
fdprint(s, "Server failed to spawn thread\n");
close(s);
}
@@ -2074,12 +2107,6 @@ static int console_state_init(void *ptr)
AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr);
-/* These gymnastics are due to platforms which designate char as unsigned by
- * default. Level is the negative character -- offset by 1, because \0 is the
- * EOS delimiter. */
-#define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
-#define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
-
static int console_print(const char *s, int local)
{
struct console_state_data *state =
@@ -2174,6 +2201,7 @@ static int ast_all_zeros(char *s)
return 1;
}
+/* This is the main console CLI command handler. Run by the main() thread. */
static void consolehandler(char *s)
{
printf("%s", term_end());
@@ -2211,38 +2239,56 @@ static int remoteconsolehandler(char *s)
else
ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
ret = 1;
- } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
- int old_verbose = option_verbose;
- if (strncasecmp(s + 17, "atleast ", 8) == 0) {
- int tmp;
- if (sscanf(s + 25, "%d", &tmp) != 1) {
- fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
- } else {
- if (tmp > option_verbose) {
- option_verbose = tmp;
- }
- if (old_verbose != option_verbose) {
- fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
- } else {
- fprintf(stdout, "Verbosity level unchanged.\n");
- }
+ } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
+ (s[4] == '\0' || isspace(s[4]))) {
+ quit_handler(0, SHUTDOWN_FAST, 0);
+ ret = 1;
+ } else if (s[0]) {
+ char *shrunk = ast_strdupa(s);
+ char *cur;
+ char *prev;
+
+ /*
+ * Remove duplicate spaces from shrunk for matching purposes.
+ *
+ * shrunk has at least one character in it to start with or we
+ * couldn't get here.
+ */
+ for (prev = shrunk, cur = shrunk + 1; *cur; ++cur) {
+ if (*prev == ' ' && *cur == ' ') {
+ /* Skip repeated space delimiter. */
+ continue;
}
- } else {
- if (sscanf(s + 17, "%d", &option_verbose) != 1) {
- fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
+ *++prev = *cur;
+ }
+ *++prev = '\0';
+
+ if (strncasecmp(shrunk, "core set verbose ", 17) == 0) {
+ /*
+ * We need to still set the rasterisk option_verbose in case we are
+ * talking to an earlier version which doesn't prefilter verbose
+ * levels. This is really a compromise as we should always take
+ * whatever the server sends.
+ */
+
+ if (!strncasecmp(shrunk + 17, "off", 3)) {
+ ast_verb_console_set(0);
} else {
- if (old_verbose != option_verbose) {
- fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
- } else {
- fprintf(stdout, "Verbosity level unchanged.\n");
+ int verbose_new;
+ int atleast;
+
+ atleast = 8;
+ if (strncasecmp(shrunk + 17, "atleast ", atleast)) {
+ atleast = 0;
+ }
+
+ if (sscanf(shrunk + 17 + atleast, "%30d", &verbose_new) == 1) {
+ if (!atleast || ast_verb_console_get() < verbose_new) {
+ ast_verb_console_set(verbose_new);
+ }
}
}
}
- ret = 1;
- } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
- (s[4] == '\0' || isspace(s[4]))) {
- quit_handler(0, SHUTDOWN_FAST, 0);
- ret = 1;
}
return ret;
@@ -2564,6 +2610,31 @@ static struct ast_cli_entry cli_asterisk[] = {
#endif /* ! LOW_MEMORY */
};
+static void send_rasterisk_connect_commands(void)
+{
+ char buf[80];
+
+ /*
+ * Tell the server asterisk instance about the verbose level
+ * initially desired.
+ */
+ if (option_verbose) {
+ snprintf(buf, sizeof(buf), "core set verbose atleast %d silent", option_verbose);
+ fdsend(ast_consock, buf);
+ }
+
+ if (option_debug) {
+ snprintf(buf, sizeof(buf), "core set debug atleast %d", option_debug);
+ fdsend(ast_consock, buf);
+ }
+
+ if (!ast_opt_mute) {
+ fdsend(ast_consock, "logger mute silent");
+ } else {
+ printf("log and verbose output currently muted ('logger mute' to unmute)\n");
+ }
+}
+
static int ast_el_read_char(EditLine *editline, char *cp)
{
int num_read = 0;
@@ -2617,10 +2688,7 @@ static int ast_el_read_char(EditLine *editline, char *cp)
fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
printf("%s", term_quit());
WELCOME_MESSAGE;
- if (!ast_opt_mute)
- fdsend(ast_consock, "logger mute silent");
- else
- printf("log and verbose output currently muted ('logger mute' to unmute)\n");
+ send_rasterisk_connect_commands();
break;
} else
usleep(1000000 / reconnects_per_second);
@@ -3171,11 +3239,7 @@ static void ast_remotecontrol(char *data)
else
pid = -1;
if (!data) {
- if (!ast_opt_mute) {
- fdsend(ast_consock, "logger mute silent");
- } else {
- printf("log and verbose output currently muted ('logger mute' to unmute)\n");
- }
+ send_rasterisk_connect_commands();
}
if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
@@ -3652,6 +3716,7 @@ static void canary_exit(void)
kill(canary_pid, SIGKILL);
}
+/* Execute CLI commands on startup. Run by main() thread. */
static void run_startup_commands(void)
{
int fd;
@@ -4082,6 +4147,9 @@ int main(int argc, char *argv[])
}
}
+ /* Initial value of the maximum active system verbosity level. */
+ ast_verb_sys_level = option_verbose;
+
if (ast_tryconnect()) {
/* One is already running */
if (ast_opt_remote) {
diff --git a/main/cli.c b/main/cli.c
index a9f466499..fa5cc987a 100644
--- a/main/cli.c
+++ b/main/cli.c
@@ -106,8 +106,6 @@ AST_RWLIST_HEAD(module_level_list, module_level);
/*! list of module names and their debug levels */
static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;
-/*! list of module names and their verbose levels */
-static struct module_level_list verbose_modules = AST_RWLIST_HEAD_INIT_VALUE;
AST_THREADSTORAGE(ast_cli_buf);
@@ -151,19 +149,7 @@ unsigned int ast_debug_get_by_module(const char *module)
unsigned int ast_verbose_get_by_module(const char *module)
{
- struct module_level *ml;
- unsigned int res = 0;
-
- AST_RWLIST_RDLOCK(&verbose_modules);
- AST_LIST_TRAVERSE(&verbose_modules, ml, entry) {
- if (!strcasecmp(ml->module, module)) {
- res = ml->level;
- break;
- }
- }
- AST_RWLIST_UNLOCK(&verbose_modules);
-
- return res;
+ return 0;
}
/*! \internal
@@ -357,14 +343,19 @@ static char *handle_core_reload(struct ast_cli_entry *e, int cmd, struct ast_cli
return CLI_SUCCESS;
}
+
/*!
- * \brief Find the debug or verbose file setting
- * \arg debug 1 for debug, 0 for verbose
+ * \brief Find the module level setting
+ *
+ * \param module Module name to look for.
+ * \param mll List to search.
+ *
+ * \retval level struct found on success.
+ * \retval NULL not found.
*/
-static struct module_level *find_module_level(const char *module, unsigned int debug)
+static struct module_level *find_module_level(const char *module, struct module_level_list *mll)
{
struct module_level *ml;
- struct module_level_list *mll = debug ? &debug_modules : &verbose_modules;
AST_LIST_TRAVERSE(mll, ml, entry) {
if (!strcasecmp(ml->module, module))
@@ -414,52 +405,77 @@ static char *complete_number(const char *partial, unsigned int min, unsigned int
return NULL;
}
-static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+static void status_debug_verbose(struct ast_cli_args *a, const char *what, int old_val, int cur_val)
+{
+ char was_buf[30];
+ const char *was;
+
+ if (old_val) {
+ snprintf(was_buf, sizeof(was_buf), "%d", old_val);
+ was = was_buf;
+ } else {
+ was = "OFF";
+ }
+
+ if (old_val == cur_val) {
+ ast_cli(a->fd, "%s is still %s.\n", what, was);
+ } else {
+ char now_buf[30];
+ const char *now;
+
+ if (cur_val) {
+ snprintf(now_buf, sizeof(now_buf), "%d", cur_val);
+ now = now_buf;
+ } else {
+ now = "OFF";
+ }
+
+ ast_cli(a->fd, "%s was %s and is now %s.\n", what, was, now);
+ }
+}
+
+static char *handle_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
int oldval;
int newlevel;
- unsigned int is_debug;
int atleast = 0;
- int fd = a->fd;
- int argc = a->argc;
- const char * const *argv = a->argv;
const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
- int *dst;
- char *what;
- struct module_level_list *mll;
struct module_level *ml;
switch (cmd) {
case CLI_INIT:
- e->command = "core set {debug|verbose}";
+ e->command = "core set debug";
e->usage =
#if !defined(LOW_MEMORY)
- "Usage: core set {debug|verbose} [atleast] <level> [module]\n"
+ "Usage: core set debug [atleast] <level> [module]\n"
#else
- "Usage: core set {debug|verbose} [atleast] <level>\n"
+ "Usage: core set debug [atleast] <level>\n"
#endif
- " core set {debug|verbose} off\n"
+ " core set debug off\n"
+ "\n"
#if !defined(LOW_MEMORY)
- " Sets level of debug or verbose messages to be displayed or\n"
+ " Sets level of debug messages to be displayed or\n"
" sets a module name to display debug messages from.\n"
#else
- " Sets level of debug or verbose messages to be displayed.\n"
+ " Sets level of debug messages to be displayed.\n"
#endif
- " 0 or off means no messages should be displayed.\n"
- " Equivalent to -d[d[...]] or -v[v[v...]] on startup\n";
+ " 0 or off means no messages should be displayed.\n"
+ " Equivalent to -d[d[...]] on startup\n";
return NULL;
case CLI_GENERATE:
- if (a->pos == 3 || (a->pos == 4 && !strcasecmp(a->argv[3], "atleast"))) {
+ if (!strcasecmp(argv3, "atleast")) {
+ atleast = 1;
+ }
+ if (a->pos == 3 || (a->pos == 4 && atleast)) {
const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
+
if (a->n < 21 && numbermatch == 0) {
return complete_number(pos, 0, 0x7fffffff, a->n);
} else if (pos[0] == '0') {
if (a->n == 0) {
return ast_strdup("0");
- } else {
- return NULL;
}
} else if (a->n == (21 - numbermatch)) {
if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
@@ -471,8 +487,11 @@ static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
return ast_strdup("atleast");
}
#if !defined(LOW_MEMORY)
- } else if (a->pos == 4 || (a->pos == 5 && !strcasecmp(argv3, "atleast"))) {
- return ast_complete_source_filename(a->pos == 4 ? S_OR(a->argv[4], "") : S_OR(a->argv[5], ""), a->n);
+ } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off"))
+ || (a->pos == 5 && atleast)) {
+ const char *pos = S_OR(a->argv[a->pos], "");
+
+ return ast_complete_source_filename(pos, a->n);
#endif
}
return NULL;
@@ -481,117 +500,200 @@ static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_arg
* we are guaranteed to be called with argc >= e->args;
*/
- if (argc <= e->args)
+ if (a->argc <= e->args) {
return CLI_SHOWUSAGE;
- if (!strcasecmp(argv[e->args - 1], "debug")) {
- dst = &option_debug;
- oldval = option_debug;
- what = "Core debug";
- is_debug = 1;
- } else {
- dst = &option_verbose;
- oldval = option_verbose;
- what = "Verbosity";
- is_debug = 0;
}
- if (argc == e->args + 1 && !strcasecmp(argv[e->args], "off")) {
+
+ if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {
newlevel = 0;
+ } else {
+ if (!strcasecmp(a->argv[e->args], "atleast")) {
+ atleast = 1;
+ }
+ if (a->argc != e->args + atleast + 1 && a->argc != e->args + atleast + 2) {
+ return CLI_SHOWUSAGE;
+ }
+ if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
+ return CLI_SHOWUSAGE;
+ }
- mll = is_debug ? &debug_modules : &verbose_modules;
+ if (a->argc == e->args + atleast + 2) {
+ /* We have specified a module name. */
+ char *mod = ast_strdupa(a->argv[e->args + atleast + 1]);
+ int mod_len = strlen(mod);
- AST_RWLIST_WRLOCK(mll);
- while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
- ast_free(ml);
- }
- ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
- AST_RWLIST_UNLOCK(mll);
+ if (3 < mod_len && !strcasecmp(mod + mod_len - 3, ".so")) {
+ mod[mod_len - 3] = '\0';
+ }
- goto done;
+ AST_RWLIST_WRLOCK(&debug_modules);
+
+ ml = find_module_level(mod, &debug_modules);
+ if (!newlevel) {
+ if (!ml) {
+ /* Specified off for a nonexistent entry. */
+ AST_RWLIST_UNLOCK(&debug_modules);
+ ast_cli(a->fd, "Core debug is still 0 for '%s'.\n", mod);
+ return CLI_SUCCESS;
+ }
+ AST_RWLIST_REMOVE(&debug_modules, ml, entry);
+ if (AST_RWLIST_EMPTY(&debug_modules)) {
+ ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+ }
+ AST_RWLIST_UNLOCK(&debug_modules);
+ ast_cli(a->fd, "Core debug was %d and has been set to 0 for '%s'.\n",
+ ml->level, mod);
+ ast_free(ml);
+ return CLI_SUCCESS;
+ }
+
+ if (ml) {
+ if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
+ ast_cli(a->fd, "Core debug is still %d for '%s'.\n", ml->level, mod);
+ AST_RWLIST_UNLOCK(&debug_modules);
+ return CLI_SUCCESS;
+ }
+ oldval = ml->level;
+ ml->level = newlevel;
+ } else {
+ ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
+ if (!ml) {
+ AST_RWLIST_UNLOCK(&debug_modules);
+ return CLI_FAILURE;
+ }
+ oldval = ml->level;
+ ml->level = newlevel;
+ strcpy(ml->module, mod);
+ AST_RWLIST_INSERT_TAIL(&debug_modules, ml, entry);
+ }
+ ast_set_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+
+ ast_cli(a->fd, "Core debug was %d and has been set to %d for '%s'.\n",
+ oldval, ml->level, ml->module);
+
+ AST_RWLIST_UNLOCK(&debug_modules);
+
+ return CLI_SUCCESS;
+ }
}
- if (!strcasecmp(argv[e->args], "atleast"))
- atleast = 1;
- if (argc != e->args + atleast + 1 && argc != e->args + atleast + 2)
- return CLI_SHOWUSAGE;
- if (sscanf(argv[e->args + atleast], "%30d", &newlevel) != 1)
- return CLI_SHOWUSAGE;
- if (argc == e->args + atleast + 2) {
- /* We have specified a module name. */
- char *mod = ast_strdupa(argv[e->args + atleast + 1]);
- if ((strlen(mod) > 3) && !strcasecmp(mod + strlen(mod) - 3, ".so")) {
- mod[strlen(mod) - 3] = '\0';
+ /* Update global debug level */
+ if (!newlevel) {
+ /* Specified level was 0 or off. */
+ AST_RWLIST_WRLOCK(&debug_modules);
+ while ((ml = AST_RWLIST_REMOVE_HEAD(&debug_modules, entry))) {
+ ast_free(ml);
}
+ ast_clear_flag(&ast_options, AST_OPT_FLAG_DEBUG_MODULE);
+ AST_RWLIST_UNLOCK(&debug_modules);
+ }
+ oldval = option_debug;
+ if (!atleast || newlevel > option_debug) {
+ option_debug = newlevel;
+ }
- mll = is_debug ? &debug_modules : &verbose_modules;
+ /* Report debug level status */
+ status_debug_verbose(a, "Core debug", oldval, option_debug);
- AST_RWLIST_WRLOCK(mll);
+ return CLI_SUCCESS;
+}
- ml = find_module_level(mod, is_debug);
- if (!newlevel) {
- if (!ml) {
- /* Specified off for a nonexistent entry. */
- AST_RWLIST_UNLOCK(mll);
- return CLI_SUCCESS;
- }
- AST_RWLIST_REMOVE(mll, ml, entry);
- if (AST_RWLIST_EMPTY(mll))
- ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
- AST_RWLIST_UNLOCK(mll);
- ast_cli(fd, "%s was %d and has been set to 0 for '%s'\n", what, ml->level, mod);
- ast_free(ml);
- return CLI_SUCCESS;
+static char *handle_verbose(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ int oldval;
+ int newlevel;
+ int atleast = 0;
+ int silent = 0;
+ const char *argv3 = a->argv ? S_OR(a->argv[3], "") : "";
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "core set verbose";
+ e->usage =
+ "Usage: core set verbose [atleast] <level> [silent]\n"
+ " core set verbose off\n"
+ "\n"
+ " Sets level of verbose messages to be displayed.\n"
+ " 0 or off means no verbose messages should be displayed.\n"
+ " The silent option means the command does not report what\n"
+ " happened to the verbose level.\n"
+ " Equivalent to -v[v[...]] on startup\n";
+ return NULL;
+
+ case CLI_GENERATE:
+ if (!strcasecmp(argv3, "atleast")) {
+ atleast = 1;
}
+ if (a->pos == 3 || (a->pos == 4 && atleast)) {
+ const char *pos = a->pos == 3 ? argv3 : S_OR(a->argv[4], "");
+ int numbermatch = (ast_strlen_zero(pos) || strchr("123456789", pos[0])) ? 0 : 21;
- if (ml) {
- if ((atleast && newlevel < ml->level) || ml->level == newlevel) {
- ast_cli(fd, "%s is %d for '%s'\n", what, ml->level, mod);
- AST_RWLIST_UNLOCK(mll);
- return CLI_SUCCESS;
+ if (a->n < 21 && numbermatch == 0) {
+ return complete_number(pos, 0, 0x7fffffff, a->n);
+ } else if (pos[0] == '0') {
+ if (a->n == 0) {
+ return ast_strdup("0");
+ }
+ } else if (a->n == (21 - numbermatch)) {
+ if (a->pos == 3 && !strncasecmp(argv3, "off", strlen(argv3))) {
+ return ast_strdup("off");
+ } else if (a->pos == 3 && !strncasecmp(argv3, "atleast", strlen(argv3))) {
+ return ast_strdup("atleast");
+ }
+ } else if (a->n == (22 - numbermatch) && a->pos == 3 && ast_strlen_zero(argv3)) {
+ return ast_strdup("atleast");
}
- oldval = ml->level;
- ml->level = newlevel;
- } else {
- ml = ast_calloc(1, sizeof(*ml) + strlen(mod) + 1);
- if (!ml) {
- AST_RWLIST_UNLOCK(mll);
- return CLI_FAILURE;
+ } else if ((a->pos == 4 && !atleast && strcasecmp(argv3, "off"))
+ || (a->pos == 5 && atleast)) {
+ const char *pos = S_OR(a->argv[a->pos], "");
+
+ if (a->n == 0 && !strncasecmp(pos, "silent", strlen(pos))) {
+ return ast_strdup("silent");
}
- oldval = ml->level;
- ml->level = newlevel;
- strcpy(ml->module, mod);
- AST_RWLIST_INSERT_TAIL(mll, ml, entry);
}
+ return NULL;
+ }
+ /* all the above return, so we proceed with the handler.
+ * we are guaranteed to be called with argc >= e->args;
+ */
- ast_set_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
+ if (a->argc <= e->args) {
+ return CLI_SHOWUSAGE;
+ }
- AST_RWLIST_UNLOCK(mll);
+ if (a->argc == e->args + 1 && !strcasecmp(a->argv[e->args], "off")) {
+ newlevel = 0;
+ } else {
+ if (!strcasecmp(a->argv[e->args], "atleast")) {
+ atleast = 1;
+ }
+ if (a->argc == e->args + atleast + 2
+ && !strcasecmp(a->argv[e->args + atleast + 1], "silent")) {
+ silent = 1;
+ }
+ if (a->argc != e->args + atleast + silent + 1) {
+ return CLI_SHOWUSAGE;
+ }
+ if (sscanf(a->argv[e->args + atleast], "%30d", &newlevel) != 1) {
+ return CLI_SHOWUSAGE;
+ }
+ }
- ast_cli(fd, "%s was %d and has been set to %d for '%s'\n", what, oldval, ml->level, ml->module);
+ /* Update verbose level */
+ oldval = ast_verb_console_get();
+ if (!atleast || newlevel > oldval) {
+ ast_verb_console_set(newlevel);
+ } else {
+ newlevel = oldval;
+ }
+ if (silent) {
+ /* Be silent after setting the level. */
return CLI_SUCCESS;
- } else if (!newlevel) {
- /* Specified level as 0 instead of off. */
- mll = is_debug ? &debug_modules : &verbose_modules;
-
- AST_RWLIST_WRLOCK(mll);
- while ((ml = AST_RWLIST_REMOVE_HEAD(mll, entry))) {
- ast_free(ml);
- }
- ast_clear_flag(&ast_options, is_debug ? AST_OPT_FLAG_DEBUG_MODULE : AST_OPT_FLAG_VERBOSE_MODULE);
- AST_RWLIST_UNLOCK(mll);
}
-done:
- if (!atleast || newlevel > *dst)
- *dst = newlevel;
- if (oldval > 0 && *dst == 0)
- ast_cli(fd, "%s is now OFF\n", what);
- else if (*dst > 0) {
- if (oldval == *dst)
- ast_cli(fd, "%s is at least %d\n", what, *dst);
- else
- ast_cli(fd, "%s was %d and is now %d\n", what, oldval, *dst);
- }
+ /* Report verbose level status */
+ status_debug_verbose(a, "Console verbose", oldval, newlevel);
return CLI_SUCCESS;
}
@@ -1684,7 +1786,8 @@ static struct ast_cli_entry cli_cli[] = {
AST_CLI_DEFINE(handle_core_set_debug_channel, "Enable/disable debugging on a channel"),
- AST_CLI_DEFINE(handle_verbose, "Set level of debug/verbose chattiness"),
+ AST_CLI_DEFINE(handle_debug, "Set level of debug chattiness"),
+ AST_CLI_DEFINE(handle_verbose, "Set level of verbose chattiness"),
AST_CLI_DEFINE(group_show_channels, "Display active channels with group(s)"),
diff --git a/main/logger.c b/main/logger.c
index 52bb5c021..3ecf2fcef 100644
--- a/main/logger.c
+++ b/main/logger.c
@@ -121,7 +121,7 @@ struct logchannel {
int disabled;
/*! syslog facility */
int facility;
- /*! Verbosity level */
+ /*! Verbosity level. (-1 if use option_verbose for the level.) */
int verbosity;
/*! Type of log channel */
enum logtypes type;
@@ -240,32 +240,48 @@ AST_THREADSTORAGE(log_buf);
static void logger_queue_init(void);
-static unsigned int make_components(const char *s, int lineno, int *verbosity)
+static void make_components(struct logchannel *chan)
{
char *w;
- unsigned int res = 0;
- char *stringp = ast_strdupa(s);
+ unsigned int logmask = 0;
+ char *stringp = ast_strdupa(chan->components);
unsigned int x;
+ int verb_level;
- *verbosity = 3;
+ /* Default to using option_verbose as the verbosity level of the logging channel. */
+ verb_level = -1;
while ((w = strsep(&stringp, ","))) {
- w = ast_skip_blanks(w);
-
+ w = ast_strip(w);
+ if (ast_strlen_zero(w)) {
+ continue;
+ }
if (!strcmp(w, "*")) {
- res = 0xFFFFFFFF;
- break;
- } else if (!strncasecmp(w, "verbose(", 8) && sscanf(w + 8, "%d)", verbosity) == 1) {
- res |= (1 << __LOG_VERBOSE);
- } else for (x = 0; x < ARRAY_LEN(levels); x++) {
- if (levels[x] && !strcasecmp(w, levels[x])) {
- res |= (1 << x);
- break;
+ logmask = 0xFFFFFFFF;
+ } else if (!strncasecmp(w, "verbose(", 8)) {
+ if (levels[__LOG_VERBOSE] && sscanf(w + 8, "%30u)", &verb_level) == 1) {
+ logmask |= (1 << __LOG_VERBOSE);
+ }
+ } else {
+ for (x = 0; x < ARRAY_LEN(levels); ++x) {
+ if (levels[x] && !strcasecmp(w, levels[x])) {
+ logmask |= (1 << x);
+ break;
+ }
}
}
}
-
- return res;
+ if (chan->type == LOGTYPE_CONSOLE) {
+ /*
+ * Force to use the root console verbose level so if the
+ * user specified any verbose level then it does not interfere
+ * with calculating the ast_verb_sys_level value.
+ */
+ chan->verbosity = -1;
+ } else {
+ chan->verbosity = verb_level;
+ }
+ chan->logmask = logmask;
}
static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno)
@@ -335,7 +351,7 @@ static struct logchannel *make_logchannel(const char *channel, const char *compo
}
chan->type = LOGTYPE_FILE;
}
- chan->logmask = make_components(chan->components, lineno, &chan->verbosity);
+ make_components(chan);
return chan;
}
@@ -840,10 +856,12 @@ static int reload_logger(int rotate, const char *altconf)
if (logfiles.queue_log) {
res = logger_queue_restart(queue_rotate);
AST_RWLIST_UNLOCK(&logchannels);
+ ast_verb_update();
ast_queue_log("NONE", "NONE", "NONE", "CONFIGRELOAD", "%s", "");
ast_verb(1, "Asterisk Queue Logger restarted\n");
} else {
AST_RWLIST_UNLOCK(&logchannels);
+ ast_verb_update();
}
return res;
@@ -1028,12 +1046,6 @@ static void ast_log_vsyslog(struct logmsg *msg)
syslog(syslog_level, "%s", buf);
}
-/* These gymnastics are due to platforms which designate char as unsigned by
- * default. Level is the negative character -- offset by 1, because \0 is the
- * EOS delimiter. */
-#define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
-#define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
-
/*! \brief Print a normal log message to the channels */
static void logger_print_normal(struct logmsg *logmsg)
{
@@ -1044,7 +1056,9 @@ static void logger_print_normal(struct logmsg *logmsg)
if (logmsg->level == __LOG_VERBOSE) {
char *tmpmsg = ast_strdupa(logmsg->message + 1);
+
level = VERBOSE_MAGIC2LEVEL(logmsg->message);
+
/* Iterate through the list of verbosers and pass them the log message string */
AST_RWLIST_RDLOCK(&verbosers);
AST_RWLIST_TRAVERSE(&verbosers, v, list)
@@ -1070,7 +1084,8 @@ static void logger_print_normal(struct logmsg *logmsg)
if (chan->disabled) {
continue;
}
- if (logmsg->level == __LOG_VERBOSE && level > chan->verbosity) {
+ if (logmsg->level == __LOG_VERBOSE
+ && (((chan->verbosity < 0) ? option_verbose : chan->verbosity)) < level) {
continue;
}
@@ -1246,6 +1261,7 @@ int init_logger(void)
/* create log channels */
init_logger_chain(0 /* locked */, NULL);
+ ast_verb_update();
logger_initialized = 1;
return 0;
@@ -1707,6 +1723,148 @@ void ast_verbose(const char *fmt, ...)
}
}
+/*! Console verbosity level node. */
+struct verb_console {
+ /*! List node link */
+ AST_LIST_ENTRY(verb_console) node;
+ /*! Console verbosity level. */
+ int *level;
+};
+
+/*! Registered console verbosity levels */
+static AST_RWLIST_HEAD_STATIC(verb_consoles, verb_console);
+
+/*! ast_verb_update() reentrancy protection lock. */
+AST_MUTEX_DEFINE_STATIC(verb_update_lock);
+
+void ast_verb_update(void)
+{
+ struct logchannel *log;
+ struct verb_console *console;
+ int verb_level;
+
+ ast_mutex_lock(&verb_update_lock);
+
+ AST_RWLIST_RDLOCK(&verb_consoles);
+
+ /* Default to the root console verbosity. */
+ verb_level = option_verbose;
+
+ /* Determine max remote console level. */
+ AST_LIST_TRAVERSE(&verb_consoles, console, node) {
+ if (verb_level < *console->level) {
+ verb_level = *console->level;
+ }
+ }
+ AST_RWLIST_UNLOCK(&verb_consoles);
+
+ /* Determine max logger channel level. */
+ AST_RWLIST_RDLOCK(&logchannels);
+ AST_RWLIST_TRAVERSE(&logchannels, log, list) {
+ if (verb_level < log->verbosity) {
+ verb_level = log->verbosity;
+ }
+ }
+ AST_RWLIST_UNLOCK(&logchannels);
+
+ ast_verb_sys_level = verb_level;
+
+ ast_mutex_unlock(&verb_update_lock);
+}
+
+/*!
+ * \internal
+ * \brief Unregister a console verbose level.
+ *
+ * \param console Which console to unregister.
+ *
+ * \return Nothing
+ */
+static void verb_console_unregister(struct verb_console *console)
+{
+ AST_RWLIST_WRLOCK(&verb_consoles);
+ console = AST_RWLIST_REMOVE(&verb_consoles, console, node);
+ AST_RWLIST_UNLOCK(&verb_consoles);
+ if (console) {
+ ast_verb_update();
+ }
+}
+
+static void verb_console_free(void *v_console)
+{
+ struct verb_console *console = v_console;
+
+ verb_console_unregister(console);
+ ast_free(console);
+}
+
+/*! Thread specific console verbosity level node. */
+AST_THREADSTORAGE_CUSTOM(my_verb_console, NULL, verb_console_free);
+
+void ast_verb_console_register(int *level)
+{
+ struct verb_console *console;
+
+ console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+ if (!console || !level) {
+ return;
+ }
+ console->level = level;
+
+ AST_RWLIST_WRLOCK(&verb_consoles);
+ AST_RWLIST_INSERT_HEAD(&verb_consoles, console, node);
+ AST_RWLIST_UNLOCK(&verb_consoles);
+ ast_verb_update();
+}
+
+void ast_verb_console_unregister(void)
+{
+ struct verb_console *console;
+
+ console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+ if (!console) {
+ return;
+ }
+ verb_console_unregister(console);
+}
+
+int ast_verb_console_get(void)
+{
+ struct verb_console *console;
+ int verb_level;
+
+ console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+ AST_RWLIST_RDLOCK(&verb_consoles);
+ if (!console) {
+ verb_level = 0;
+ } else if (console->level) {
+ verb_level = *console->level;
+ } else {
+ verb_level = option_verbose;
+ }
+ AST_RWLIST_UNLOCK(&verb_consoles);
+ return verb_level;
+}
+
+void ast_verb_console_set(int verb_level)
+{
+ struct verb_console *console;
+
+ console = ast_threadstorage_get(&my_verb_console, sizeof(*console));
+ if (!console) {
+ return;
+ }
+
+ AST_RWLIST_WRLOCK(&verb_consoles);
+ if (console->level) {
+ *console->level = verb_level;
+ } else {
+ option_verbose = verb_level;
+ }
+ AST_RWLIST_UNLOCK(&verb_consoles);
+ ast_verb_update();
+}
+
int ast_register_verbose(void (*v)(const char *string))
{
struct verb *verb;
@@ -1750,7 +1908,7 @@ static void update_logchannels(void)
global_logmask = 0;
AST_RWLIST_TRAVERSE(&logchannels, cur, list) {
- cur->logmask = make_components(cur->components, cur->lineno, &cur->verbosity);
+ make_components(cur);
global_logmask |= cur->logmask;
}
diff --git a/main/manager.c b/main/manager.c
index 15f10f7ed..0b6cffee5 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -1860,13 +1860,13 @@ static struct ast_manager_user *get_manager_by_name_locked(const char *name)
* \param session manager session to get parameter from.
* \return displayconnects config option value.
*/
-static int manager_displayconnects (struct mansession_session *session)
+static int manager_displayconnects(struct mansession_session *session)
{
struct ast_manager_user *user = NULL;
int ret = 0;
AST_RWLIST_RDLOCK(&users);
- if ((user = get_manager_by_name_locked (session->username))) {
+ if ((user = get_manager_by_name_locked(session->username))) {
ret = user->displayconnects;
}
AST_RWLIST_UNLOCK(&users);
@@ -5888,7 +5888,9 @@ static void purge_sessions(int n_max)
while ((session = ao2_iterator_next(&i)) && n_max > 0) {
ao2_lock(session);
if (session->sessiontimeout && (now > session->sessiontimeout) && !session->inuse) {
- if (session->authenticated && manager_displayconnects(session)) {
+ if (session->authenticated
+ && VERBOSITY_ATLEAST(2)
+ && manager_displayconnects(session)) {
ast_verb(2, "HTTP Manager '%s' timed out from %s\n",
session->username, ast_sockaddr_stringify_addr(&session->addr));
}
diff --git a/main/pbx.c b/main/pbx.c
index c5eb5f116..ae857e9b3 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -4886,7 +4886,7 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
}
ast_debug(1, "Launching '%s'\n", app->name);
- {
+ if (VERBOSITY_ATLEAST(3)) {
ast_verb(3, "Executing [%s@%s:%d] " COLORIZE_FMT "(\"" COLORIZE_FMT "\", \"" COLORIZE_FMT "\") %s\n",
exten, context, priority,
COLORIZE(COLOR_BRCYAN, 0, app->name),