Add a massive set of changes for converting to use the ast_debug() macro.
[asterisk/asterisk.git] / main / asterisk.c
index 14b9f77..4f5ada9 100644 (file)
@@ -61,6 +61,8 @@
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
+#undef sched_setscheduler
+#undef setpriority
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/time.h>
@@ -78,14 +80,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <grp.h>
 #include <pwd.h>
 #include <sys/stat.h>
-#ifdef linux
-#include <sys/prctl.h>
+#if defined(HAVE_SYSINFO)
+#include <sys/sysinfo.h>
 #endif
-#include <regex.h>
-
 #ifdef linux
 #include <sys/prctl.h>
-#endif
+#ifdef HAVE_CAP
+#include <sys/capability.h>
+#endif /* HAVE_CAP */
+#endif /* linux */
+#include <regex.h>
 
 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
 #include <netdb.h>
@@ -122,6 +126,7 @@ int daemon(int, int);  /* defined in libresolv of all places */
 #include "asterisk/version.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/devicestate.h"
+#include "asterisk/module.h"
 
 #include "asterisk/doxyref.h"          /* Doxygen documentation */
 
@@ -137,30 +142,34 @@ int daemon(int, int);  /* defined in libresolv of all places */
 
 /*! \brief Welcome message when starting a CLI interface */
 #define WELCOME_MESSAGE \
-       ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
-       ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
-       ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
-       ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
-       ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
-       ast_verbose("certain conditions. Type 'show license' for details.\n"); \
-       ast_verbose("=========================================================================\n")
-
-/*! \defgroup main_options 
+    ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2007 Digium, Inc. and others.\n" \
+                "Created by Mark Spencer <markster@digium.com>\n" \
+                "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
+                "This is free software, with components licensed under the GNU General Public\n" \
+                "License version 2 and other licenses; you are welcome to redistribute it under\n" \
+                "certain conditions. Type 'core show license' for details.\n" \
+                "=========================================================================\n" \
+                "NOTE: This is a development version of Asterisk, and should not be used in\n" \
+                "production installations.\n");
+
+/*! \defgroup main_options Main Configuration Options
  \brief Main configuration options from \ref Config_ast "asterisk.conf" or 
   the operating system command line when starting Asterisk 
   Some of them can be changed in the CLI 
  */
 /*! @{ */
 
-extern int ast_language_is_prefix;     /* XXX move to some header */
-
 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
 
-int option_verbose = 0;                                /*!< Verbosity level */
-int option_debug = 0;                          /*!< Debug level */
+int option_verbose;                            /*!< Verbosity level */
+int option_debug;                              /*!< Debug level */
 
-double option_maxload = 0.0;                   /*!< Max load avg on system */
-int option_maxcalls = 0;                       /*!< Max number of active calls */
+double option_maxload;                         /*!< Max load avg on system */
+int option_maxcalls;                           /*!< Max number of active calls */
+int option_maxfiles;                           /*!< Max number of open file handles (files, sockets) */
+#if defined(HAVE_SYSINFO)
+long option_minmemfree;                                /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
+#endif
 
 /*! @} */
 
@@ -187,8 +196,8 @@ static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
 time_t ast_startuptime;
 time_t ast_lastreloadtime;
 
-static History *el_hist = NULL;
-static EditLine *el = NULL;
+static History *el_hist;
+static EditLine *el;
 static char *remotehostname;
 
 struct console consoles[AST_MAX_CONNECTS];
@@ -229,12 +238,18 @@ extern const char *ast_build_date;
 extern const char *ast_build_user;
 
 static char *_argv[256];
-static int shuttingdown = 0;
-static int restartnow = 0;
+static int shuttingdown;
+static int restartnow;
 static pthread_t consolethread = AST_PTHREADT_NULL;
 
 static char randompool[256];
 
+static int sig_alert_pipe[2] = { -1, -1 };
+static struct {
+        unsigned int need_reload:1;
+        unsigned int need_quit:1;
+} sig_flags;
+
 #if !defined(LOW_MEMORY)
 struct file_version {
        AST_LIST_ENTRY(file_version) list;
@@ -278,8 +293,9 @@ void ast_unregister_file_version(const char *file)
        }
        AST_LIST_TRAVERSE_SAFE_END;
        AST_LIST_UNLOCK(&file_versions);
+
        if (find)
-               free(find);
+               ast_free(find);
 }
 
 struct thread_list_t {
@@ -290,8 +306,8 @@ struct thread_list_t {
 
 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
 
-static char show_threads_help[] =
-"Usage: show threads\n"
+static const char show_threads_help[] =
+"Usage: core show threads\n"
 "       List threads currently active in the system.\n";
 
 void ast_register_thread(char *name)
@@ -301,7 +317,7 @@ void ast_register_thread(char *name)
        if (!new)
                return;
        new->id = pthread_self();
-       new->name = name; /* this was a copy already */
+       new->name = name; /* steal the allocated memory for the thread name */
        AST_LIST_LOCK(&thread_list);
        AST_LIST_INSERT_HEAD(&thread_list, new, list);
        AST_LIST_UNLOCK(&thread_list);
@@ -313,7 +329,7 @@ void ast_unregister_thread(void *id)
 
        AST_LIST_LOCK(&thread_list);
        AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
-               if ((void *)x->id == id) {
+               if ((void *) x->id == id) {
                        AST_LIST_REMOVE_CURRENT(&thread_list, list);
                        break;
                }
@@ -321,11 +337,72 @@ void ast_unregister_thread(void *id)
        AST_LIST_TRAVERSE_SAFE_END;
        AST_LIST_UNLOCK(&thread_list);
        if (x) {
-               free(x->name);
-               free(x);
+               ast_free(x->name);
+               ast_free(x);
        }
 }
 
+/*! \brief Give an overview of core settings */
+static int handle_show_settings(int fd, int argc, char *argv[])
+{
+       char buf[BUFSIZ];
+       struct tm tm;
+
+       ast_cli(fd, "\nPBX Core settings\n");
+       ast_cli(fd, "-----------------\n");
+       ast_cli(fd, "  Version:                     %s\n", "" ASTERISK_VERSION "" );
+       if (option_maxcalls)
+               ast_cli(fd, "  Max. calls:                  %d (Current %d)\n", option_maxcalls, ast_active_channels());
+       else
+               ast_cli(fd, "  Max. calls:                  Not set\n");
+       if (option_maxfiles)
+               ast_cli(fd, "  Max. open file handles:      %d\n", option_maxfiles); 
+       else
+               ast_cli(fd, "  Max. open file handles:      Not set\n");
+       ast_cli(fd, "  Verbosity:                   %d\n", option_verbose);
+       ast_cli(fd, "  Debug level:                 %d\n", option_debug);
+       ast_cli(fd, "  Max load avg:                %lf\n", option_maxload);
+#if defined(HAVE_SYSINFO)
+       ast_cli(fd, "  Min Free Memory:             %ld MB\n", option_minmemfree);
+#endif
+       if (localtime_r(&ast_startuptime, &tm)) {
+               strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
+               ast_cli(fd, "  Startup time:                %s\n", buf);
+       }
+       if (localtime_r(&ast_lastreloadtime, &tm)) {
+               strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
+               ast_cli(fd, "  Last reload time:            %s\n", buf);
+       }
+       ast_cli(fd, "  System:                      %s/%s built by %s on %s %s\n", ast_build_os, ast_build_kernel, ast_build_user, ast_build_machine, ast_build_date);
+       ast_cli(fd, "  System name:                 %s\n", ast_config_AST_SYSTEM_NAME);
+       ast_cli(fd, "  Default language:            %s\n", defaultlanguage);
+       ast_cli(fd, "  Language prefix:             %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
+       ast_cli(fd, "  User name and group:         %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
+       ast_cli(fd, "  Executable includes:         %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
+       ast_cli(fd, "  Transcode via SLIN:          %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
+       ast_cli(fd, "  Internal timing:             %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
+       ast_cli(fd, "  Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
+
+       ast_cli(fd, "\n* Subsystems\n");
+       ast_cli(fd, "  -------------\n");
+       ast_cli(fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
+       ast_cli(fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
+       ast_cli(fd, "  Call data records:           %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
+       ast_cli(fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
+
+       /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */
+
+       ast_cli(fd, "\n* Directories\n");
+       ast_cli(fd, "  -------------\n");
+       ast_cli(fd, "  Configuration file:          %s\n", ast_config_AST_CONFIG_FILE);
+       ast_cli(fd, "  Configuration directory:     %s\n", ast_config_AST_CONFIG_DIR);
+       ast_cli(fd, "  Module directory:            %s\n", ast_config_AST_MODULE_DIR);
+       ast_cli(fd, "  Spool directory:             %s\n", ast_config_AST_SPOOL_DIR);
+       ast_cli(fd, "  Log directory:               %s\n", ast_config_AST_LOG_DIR);
+       ast_cli(fd, "\n\n");
+       return 0;
+}
+
 static int handle_show_threads(int fd, int argc, char *argv[])
 {
        int count = 0;
@@ -341,6 +418,33 @@ static int handle_show_threads(int fd, int argc, char *argv[])
        return 0;
 }
 
+#if defined(HAVE_SYSINFO)
+static const char show_sysinfo_help[] =
+"Usage: core show sysinfo\n"
+"       List current system information.\n";
+
+/*! \brief Give an overview of system statistics */
+static int handle_show_sysinfo(int fd, int argc, char *argv[])
+{
+       struct sysinfo sys_info;
+
+       if (sysinfo(&sys_info)) {
+               ast_cli(fd, "FAILED to retrieve system information\n\n");
+               return 0;
+       }
+       ast_cli(fd, "\nSystem Statistics\n");
+       ast_cli(fd, "-----------------\n");
+       ast_cli(fd, "  System Uptime:             %ld hours\n", sys_info.uptime/3600);
+       ast_cli(fd, "  Total RAM:                 %ld KiB\n", (sys_info.totalram / sys_info.mem_unit)/1024);
+       ast_cli(fd, "  Free RAM:                  %ld KiB\n", (sys_info.freeram / sys_info.mem_unit)/1024);
+       ast_cli(fd, "  Buffer RAM:                %ld KiB\n", (sys_info.bufferram / sys_info.mem_unit)/1024);
+       ast_cli(fd, "  Total Swap Space:          %ld KiB\n", (sys_info.totalswap / sys_info.mem_unit)/1024);
+       ast_cli(fd, "  Free Swap Space:           %ld KiB\n\n", (sys_info.freeswap / sys_info.mem_unit)/1024);
+       ast_cli(fd, "  Number of Processes:       %d \n\n", sys_info.procs);
+       return 0;
+}
+#endif
+
 struct profile_entry {
        const char *name;
        uint64_t        scale;  /* if non-zero, values are scaled by this */
@@ -448,17 +552,17 @@ static int handle_show_profile(int fd, int argc, char *argv[])
 
        min = 0;
        max = prof_data->entries;
-       if  (argc >= 3) { /* specific entries */
-               if (isdigit(argv[2][0])) {
-                       min = atoi(argv[2]);
-                       if (argc == 4 && strcmp(argv[3], "-"))
-                               max = atoi(argv[3]);
+       if  (argc > 3) { /* specific entries */
+               if (isdigit(argv[3][0])) {
+                       min = atoi(argv[3]);
+                       if (argc == 5 && strcmp(argv[4], "-"))
+                               max = atoi(argv[4]);
                } else
-                       search = argv[2];
+                       search = argv[3];
        }
        if (max > prof_data->entries)
                max = prof_data->entries;
-       if (!strcmp(argv[0], "clear")) {
+       if (!strcmp(argv[1], "clear")) {
                for (i= min; i < max; i++) {
                        if (!search || strstr(prof_data->e[i].name, search)) {
                                prof_data->e[i].value = 0;
@@ -469,10 +573,12 @@ static int handle_show_profile(int fd, int argc, char *argv[])
        }
        ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
                prof_data->entries, prof_data->max_size);
+       ast_cli(fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
+                       "Value", "Average", "Name");
        for (i = min; i < max; i++) {
                struct profile_entry *e = &prof_data->e[i];
                if (!search || strstr(prof_data->e[i].name, search))
-                   ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
+                   ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
                        i,
                        (long)e->scale,
                        (long)e->events, (long long)e->value,
@@ -482,9 +588,9 @@ static int handle_show_profile(int fd, int argc, char *argv[])
        return 0;
 }
 
-static char show_version_files_help[] = 
-"Usage: show version files [like <pattern>]\n"
-"       Shows the revision numbers of the files used to build this copy of Asterisk.\n"
+static const char show_version_files_help[] = 
+"Usage: core show file version [like <pattern>]\n"
+"       Lists the revision numbers of the files used to build this copy of Asterisk.\n"
 "       Optional regular expression pattern is used to filter the file list.\n";
 
 /*! \brief CLI command to list module versions */
@@ -498,18 +604,18 @@ static int handle_show_version_files(int fd, int argc, char *argv[])
        int count_files = 0;
 
        switch (argc) {
-       case 5:
-               if (!strcasecmp(argv[3], "like")) {
-                       if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
+       case 6:
+               if (!strcasecmp(argv[4], "like")) {
+                       if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
                                return RESULT_SHOWUSAGE;
                        havepattern = 1;
                } else
                        return RESULT_SHOWUSAGE;
                break;
-       case 4:
+       case 5:
                havename = 1;
                break;
-       case 3:
+       case 4:
                break;
        default:
                return RESULT_SHOWUSAGE;
@@ -519,7 +625,7 @@ static int handle_show_version_files(int fd, int argc, char *argv[])
        ast_cli(fd, FORMAT, "----", "--------");
        AST_LIST_LOCK(&file_versions);
        AST_LIST_TRAVERSE(&file_versions, iterator, list) {
-               if (havename && strcasecmp(iterator->file, argv[3]))
+               if (havename && strcasecmp(iterator->file, argv[4]))
                        continue;
 
                if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
@@ -642,26 +748,34 @@ void ast_unreplace_sigchld(void)
 int ast_safe_system(const char *s)
 {
        pid_t pid;
+#ifdef HAVE_WORKING_FORK
        int x;
+#endif
        int res;
        struct rusage rusage;
        int status;
 
-#if HAVE_WORKING_FORK
-       ast_replace_sigchld();
+#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
+       ast_replace_sigchld();
 
+#ifdef HAVE_WORKING_FORK
        pid = fork();
+#else
+       pid = vfork();
+#endif 
 
        if (pid == 0) {
+#ifdef HAVE_WORKING_FORK
                if (ast_opt_high_priority)
                        ast_set_priority(0);
                /* Close file descriptors and launch system command */
                for (x = STDERR_FILENO + 1; x < 4096; x++)
                        close(x);
+#endif
                execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
-               exit(1);
+               _exit(1);
        } else if (pid > 0) {
-               for(;;) {
+               for (;;) {
                        res = wait4(pid, &status, 0, &rusage);
                        if (res > -1) {
                                res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
@@ -769,7 +883,7 @@ static void *netconsole(void *vconsole)
                ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
        snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
        fdprint(con->fd, tmp);
-       for(;;) {
+       for (;;) {
                fds[0].fd = con->fd;
                fds[0].events = POLLIN;
                fds[0].revents = 0;
@@ -820,9 +934,6 @@ static void *listener(void *unused)
        int x;
        int flags;
        struct pollfd fds[1];
-       pthread_attr_t attr;
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        for (;;) {
                if (ast_socket < 0)
                        return NULL;
@@ -854,7 +965,7 @@ static void *listener(void *unused)
                                        fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
                                        consoles[x].fd = s;
                                        consoles[x].mute = ast_opt_mute;
-                                       if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
+                                       if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
                                                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]);
@@ -912,24 +1023,22 @@ static int ast_makesocket(void)
                return -1;
        }
        ast_register_verbose(network_verboser);
-       ast_pthread_create(&lthread, NULL, listener, NULL);
+       ast_pthread_create_background(&lthread, NULL, listener, NULL);
 
        if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
                struct passwd *pw;
-               if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
+               if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
                        ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
-               } else {
+               else
                        uid = pw->pw_uid;
-               }
        }
                
        if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
                struct group *grp;
-               if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
+               if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
                        ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
-               } else {
+               else
                        gid = grp->gr_gid;
-               }
        }
 
        if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
@@ -982,12 +1091,14 @@ static void urg_handler(int num)
 
 static void hup_handler(int num)
 {
+       int a = 0;
        if (option_verbose > 1) 
                printf("Received HUP signal -- Reloading configs\n");
        if (restartnow)
                execvp(_argv[0], _argv);
-       /* XXX This could deadlock XXX */
-       ast_module_reload(NULL);
+       sig_flags.need_reload = 1;
+       if (sig_alert_pipe[1] != -1)
+               write(sig_alert_pipe[1], &a, sizeof(a));
        signal(num, hup_handler);
 }
 
@@ -1006,6 +1117,29 @@ static void child_handler(int sig)
        signal(sig, child_handler);
 }
 
+/*! \brief Set maximum open files */
+static void set_ulimit(int value)
+{
+       struct rlimit l = {0, 0};
+       
+       if (value <= 0) {
+               ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
+               return;
+       }
+       
+       l.rlim_cur = value;
+       l.rlim_max = value;
+       
+       if (setrlimit(RLIMIT_NOFILE, &l)) {
+               ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
+               return;
+       }
+       
+       ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
+       
+       return;
+}
+
 /*! \brief Set an X-term or screen title */
 static void set_title(char *text)
 {
@@ -1036,10 +1170,8 @@ int ast_set_priority(int pri)
                                ast_verbose("Set to realtime thread\n");
        } else {
                sched.sched_priority = 0;
-               if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
-                       ast_log(LOG_WARNING, "Unable to set normal priority\n");
-                       return -1;
-               }
+               /* According to the manpage, these parameters can never fail. */
+               sched_setscheduler(0, SCHED_OTHER, &sched);
        }
 #else
        if (pri) {
@@ -1050,10 +1182,8 @@ int ast_set_priority(int pri)
                        if (option_verbose)
                                ast_verbose("Set to high priority\n");
        } else {
-               if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
-                       ast_log(LOG_WARNING, "Unable to set normal priority\n");
-                       return -1;
-               }
+               /* According to the manpage, these parameters can never fail. */
+               setpriority(PRIO_PROCESS, 0, 0);
        }
 #endif
        return 0;
@@ -1116,6 +1246,9 @@ static void quit_handler(int num, int nice, int safeshutdown, int restart)
                                ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
                        return;
                }
+
+               if (nice)
+                       ast_module_shutdown();
        }
        if (ast_opt_console || ast_opt_remote) {
                if (getenv("HOME")) 
@@ -1133,8 +1266,7 @@ static void quit_handler(int num, int nice, int safeshutdown, int restart)
        /* Called on exit */
        if (option_verbose && ast_opt_console)
                ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
-       else if (option_debug)
-               ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
+       ast_debug(1, "Asterisk ending (%d).\n", num);
        manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
        if (ast_socket > -1) {
                pthread_cancel(lthread);
@@ -1155,7 +1287,7 @@ static void quit_handler(int num, int nice, int safeshutdown, int restart)
                        fcntl(x, F_SETFD, FD_CLOEXEC);
                }
                if (option_verbose || ast_opt_console)
-                       ast_verbose("Restarting Asterisk NOW...\n");
+                       ast_verbose("Asterisk is now restarting...\n");
                restartnow = 1;
 
                /* close logger */
@@ -1179,7 +1311,12 @@ static void quit_handler(int num, int nice, int safeshutdown, int restart)
 
 static void __quit_handler(int num)
 {
-       quit_handler(num, 0, 1, 0);
+       int a = 0;
+       sig_flags.need_quit = 1;
+       if (sig_alert_pipe[1] != -1)
+               write(sig_alert_pipe[1], &a, sizeof(a));
+       /* There is no need to restore the signal handler here, since the app
+        * is going to exit */
 }
 
 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
@@ -1266,57 +1403,63 @@ static int remoteconsolehandler(char *s)
        return ret;
 }
 
-static char abort_halt_help[] = 
+static const char abort_halt_help[] = 
 "Usage: abort shutdown\n"
 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
 "       call operations.\n";
 
-static char shutdown_now_help[] = 
+static const char shutdown_now_help[] = 
 "Usage: stop now\n"
 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
 
-static char shutdown_gracefully_help[] = 
+static const char shutdown_gracefully_help[] = 
 "Usage: stop gracefully\n"
 "       Causes Asterisk to not accept new calls, and exit when all\n"
 "       active calls have terminated normally.\n";
 
-static char shutdown_when_convenient_help[] = 
+static const char shutdown_when_convenient_help[] = 
 "Usage: stop when convenient\n"
 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
 
-static char restart_now_help[] = 
+static const char restart_now_help[] = 
 "Usage: restart now\n"
 "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
 "       restart.\n";
 
-static char restart_gracefully_help[] = 
+static const char restart_gracefully_help[] = 
 "Usage: restart gracefully\n"
 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
 "       restart when all active calls have ended.\n";
 
-static char restart_when_convenient_help[] = 
+static const char restart_when_convenient_help[] = 
 "Usage: restart when convenient\n"
 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
 
-static char bang_help[] =
+static const char bang_help[] =
 "Usage: !<command>\n"
 "       Executes a given shell command\n";
 
-static char show_warranty_help[] =
-"Usage: show warranty\n"
-"      Shows the warranty (if any) for this copy of Asterisk.\n";
+static const char show_warranty_help[] =
+"Usage: core show warranty\n"
+"       Shows the warranty (if any) for this copy of Asterisk.\n";
 
-static char show_license_help[] =
-"Usage: show license\n"
-"      Shows the license(s) for this copy of Asterisk.\n";
+static const char show_license_help[] =
+"Usage: core show license\n"
+"       Shows the license(s) for this copy of Asterisk.\n";
 
-static char version_help[] =
-"Usage: show version\n"
+static const char version_help[] =
+"Usage: core show version\n"
 "       Shows Asterisk version information.\n";
 
+#if defined(MARKO_BDAY)
+static const char markobday_help[] =
+"Usage: marko show birthday\n"
+"       Shows time until/since Mark Spencer's 30th birthday.\n";
+#endif
+
 static int handle_version(int fd, int argc, char *argv[])
 {
-       if (argc != 2)
+       if (argc != 3)
                return RESULT_SHOWUSAGE;
        ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
                ASTERISK_VERSION, ast_build_user, ast_build_hostname,
@@ -1324,6 +1467,73 @@ static int handle_version(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 }
 
+#if defined(MARKO_BDAY)
+static void print_markobdaystr(int fd, time_t timeval, const char *prefix)
+{
+       int x; /* the main part - years, weeks, etc. */
+       struct ast_str *out;
+
+#define SECOND (1)
+#define MINUTE (SECOND*60)
+#define HOUR (MINUTE*60)
+#define DAY (HOUR*24)
+#define WEEK (DAY*7)
+#define YEAR (DAY*365)
+#define NEEDCOMMA(x) ((x)? ",": "")    /* define if we need a comma */
+       if (timeval < 0)        /* invalid, nothing to show */
+               return;
+
+       out = ast_str_alloca(256);
+       if (timeval > YEAR) {
+               x = (timeval / YEAR);
+               timeval -= (x * YEAR);
+               ast_str_append(&out, 0, "%d year%s%s ", x, ESS(x),NEEDCOMMA(timeval));
+       }
+       if (timeval > WEEK) {
+               x = (timeval / WEEK);
+               timeval -= (x * WEEK);
+               ast_str_append(&out, 0, "%d week%s%s ", x, ESS(x),NEEDCOMMA(timeval));
+       }
+       if (timeval > DAY) {
+               x = (timeval / DAY);
+               timeval -= (x * DAY);
+               ast_str_append(&out, 0, "%d day%s%s ", x, ESS(x),NEEDCOMMA(timeval));
+       }
+       if (timeval > HOUR) {
+               x = (timeval / HOUR);
+               timeval -= (x * HOUR);
+               ast_str_append(&out, 0, "%d hour%s%s ", x, ESS(x),NEEDCOMMA(timeval));
+       }
+       if (timeval > MINUTE) {
+               x = (timeval / MINUTE);
+               timeval -= (x * MINUTE);
+               ast_str_append(&out, 0, "%d minute%s%s ", x, ESS(x),NEEDCOMMA(timeval));
+       }
+       x = timeval;
+       if (x > 0 || out->used == 0)    /* if there is nothing, print 0 seconds */
+               ast_str_append(&out, 0, "%d second%s ", x, ESS(x));
+       ast_cli(fd, "%s: %s\n", prefix, out->str);
+}
+
+static int handle_markobday(int fd, int argc, char *argv[])
+{
+       time_t markobdaystarttime = 1176008400; /* 2007-04-08 00:00:00 */
+       time_t markobdayendtime = 1176094799;   /* 2007-04-08 23:59:59 */
+       time_t curtime;
+
+       curtime = time(NULL);
+       if (markobdaystarttime && markobdayendtime) {
+               if (curtime >= markobdaystarttime && curtime <= markobdayendtime)
+                       ast_cli(fd, "Happy 30th birthday Marko!\n");
+               else if (curtime > markobdayendtime)
+                       print_markobdaystr(fd, curtime - markobdayendtime, "Time since Mark Spencer's 30th birthday");
+               else
+                       print_markobdaystr(fd, markobdaystarttime - curtime, "Time until Mark Spencer's 30th birthday");
+       }
+       return RESULT_SUCCESS;
+}
+#endif
+
 #if 0
 static int handle_quit(int fd, int argc, char *argv[])
 {
@@ -1397,66 +1607,60 @@ static int handle_bang(int fd, int argc, char *argv[])
 {
        return RESULT_SUCCESS;
 }
-static const char *warranty_lines[] = {
-       "\n",
-       "                           NO WARRANTY\n",
-       "\n",
-       "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
-       "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
-       "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
-       "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
-       "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
-       "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
-       "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
-       "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
-       "REPAIR OR CORRECTION.\n",
-       "\n",
-       "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
-       "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
-       "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
-       "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
-       "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
-       "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
-       "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
-       "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
-       "POSSIBILITY OF SUCH DAMAGES.\n",
+static const char warranty_lines[] = {
+       "\n"
+       "                           NO WARRANTY\n"
+       "\n"
+       "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
+       "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
+       "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
+       "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
+       "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
+       "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
+       "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
+       "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
+       "REPAIR OR CORRECTION.\n"
+       "\n"
+       "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
+       "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
+       "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
+       "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
+       "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
+       "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
+       "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
+       "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
+       "POSSIBILITY OF SUCH DAMAGES.\n"
 };
 
 static int show_warranty(int fd, int argc, char *argv[])
 {
-       int x;
-
-       for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
-               ast_cli(fd, (char *) warranty_lines[x]);
+       ast_cli(fd, warranty_lines);
 
        return RESULT_SUCCESS;
 }
 
-static const char *license_lines[] = {
-       "\n",
-       "This program is free software; you can redistribute it and/or modify\n",
-       "it under the terms of the GNU General Public License version 2 as\n",
-       "published by the Free Software Foundation.\n",
-       "\n",
-       "This program also contains components licensed under other licenses.\n",
-       "They include:\n",
-       "\n",
-       "This program is distributed in the hope that it will be useful,\n",
-       "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
-       "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
-       "GNU General Public License for more details.\n",
-       "\n",
-       "You should have received a copy of the GNU General Public License\n",
-       "along with this program; if not, write to the Free Software\n",
-       "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n",
+static const char license_lines[] = {
+       "\n"
+       "This program is free software; you can redistribute it and/or modify\n"
+       "it under the terms of the GNU General Public License version 2 as\n"
+       "published by the Free Software Foundation.\n"
+       "\n"
+       "This program also contains components licensed under other licenses.\n"
+       "They include:\n"
+       "\n"
+       "This program is distributed in the hope that it will be useful,\n"
+       "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+       "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+       "GNU General Public License for more details.\n"
+       "\n"
+       "You should have received a copy of the GNU General Public License\n"
+       "along with this program; if not, write to the Free Software\n"
+       "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
 };
 
 static int show_license(int fd, int argc, char *argv[])
 {
-       int x;
-
-       for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
-               ast_cli(fd, (char *) license_lines[x]);
+       ast_cli(fd, license_lines);
 
        return RESULT_SUCCESS;
 }
@@ -1465,38 +1669,82 @@ static int show_license(int fd, int argc, char *argv[])
 
 #define ASTERISK_PROMPT2 "%s*CLI> "
 
-static struct ast_cli_entry core_cli[] = {
-       { { "abort", "halt", NULL }, handle_abort_halt,
-         "Cancel a running halt", abort_halt_help },
-       { { "stop", "now", NULL }, handle_shutdown_now,
-         "Shut down Asterisk immediately", shutdown_now_help },
-       { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
-         "Gracefully shut down Asterisk", shutdown_gracefully_help },
-       { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
-         "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
-       { { "restart", "now", NULL }, handle_restart_now,
-         "Restart Asterisk immediately", restart_now_help },
-       { { "restart", "gracefully", NULL }, handle_restart_gracefully,
-         "Restart Asterisk gracefully", restart_gracefully_help },
-       { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
-         "Restart Asterisk at empty call volume", restart_when_convenient_help },
-       { { "show", "warranty", NULL }, show_warranty,
-         "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
-       { { "show", "license", NULL }, show_license,
-         "Show the license(s) for this copy of Asterisk", show_license_help },
-       { { "show", "version", NULL }, handle_version, 
-         "Display version info", version_help },
-       { { "!", NULL }, handle_bang,
-         "Execute a shell command", bang_help },
+static struct ast_cli_entry cli_asterisk[] = {
+       { { "abort", "halt", NULL },
+       handle_abort_halt, "Cancel a running halt",
+       abort_halt_help },
+
+       { { "stop", "now", NULL },
+       handle_shutdown_now, "Shut down Asterisk immediately",
+       shutdown_now_help },
+
+       { { "stop", "gracefully", NULL },
+       handle_shutdown_gracefully, "Gracefully shut down Asterisk",
+       shutdown_gracefully_help },
+
+       { { "stop", "when", "convenient", NULL },
+       handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
+       shutdown_when_convenient_help },
+
+       { { "restart", "now", NULL },
+       handle_restart_now, "Restart Asterisk immediately", restart_now_help },
+
+       { { "restart", "gracefully", NULL },
+       handle_restart_gracefully, "Restart Asterisk gracefully",
+       restart_gracefully_help },
+
+       { { "restart", "when", "convenient", NULL },
+       handle_restart_when_convenient, "Restart Asterisk at empty call volume",
+       restart_when_convenient_help },
+
+       { { "core", "show", "warranty", NULL },
+       show_warranty, "Show the warranty (if any) for this copy of Asterisk",
+       show_warranty_help },
+
+       { { "core", "show", "license", NULL },
+       show_license, "Show the license(s) for this copy of Asterisk",
+       show_license_help },
+
+       { { "core", "show", "version", NULL },
+       handle_version, "Display version info",
+       version_help },
+
+#if defined(MARKO_BDAY)
+       { { "marko", "show", "birthday", NULL },
+       handle_markobday, "Display time until/since Mark Spencer's 30th birthday",
+       markobday_help },
+#endif
+
+       { { "!", NULL },
+       handle_bang, "Execute a shell command",
+       bang_help },
+
 #if !defined(LOW_MEMORY)
-       { { "show", "version", "files", NULL }, handle_show_version_files,
-         "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
-       { { "show", "threads", NULL }, handle_show_threads,
-         "Show running threads", show_threads_help, NULL },
-       { { "show", "profile", NULL }, handle_show_profile,
-         "Show profiling info"},
-       { { "clear", "profile", NULL }, handle_show_profile,
-         "Clear profiling info"},
+       { { "core", "show", "file", "version", NULL },
+       handle_show_version_files, "List versions of files used to build Asterisk",
+       show_version_files_help, complete_show_version_files },
+
+       { { "core", "show", "threads", NULL },
+       handle_show_threads, "Show running threads",
+       show_threads_help },
+
+#if defined(HAVE_SYSINFO)
+       { { "core", "show", "sysinfo", NULL },
+       handle_show_sysinfo, "Show System Information",
+       show_sysinfo_help },
+#endif
+
+       { { "core", "show", "profile", NULL },
+       handle_show_profile, "Display profiling info",
+       NULL },
+
+       { { "core", "show", "settings", NULL },
+       handle_show_settings, "Show some core settings",
+       NULL },
+
+       { { "core", "clear", "profile", NULL },
+       handle_show_profile, "Clear profiling info",
+       NULL },
 #endif /* ! LOW_MEMORY */
 };
 
@@ -1550,9 +1798,8 @@ static int ast_el_read_char(EditLine *el, char *cp)
                                                        printf(term_quit());
                                                        WELCOME_MESSAGE;
                                                        break;
-                                               } else {
+                                               } else
                                                        usleep(1000000 / reconnects_per_second);
-                                               }
                                        }
                                        if (tries >= 30 * reconnects_per_second) {
                                                fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
@@ -1569,9 +1816,8 @@ static int ast_el_read_char(EditLine *el, char *cp)
                        if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
                                *cp = CC_REFRESH;
                                return(1);
-                       } else {
+                       } else
                                lastpos = 1;
-                       }
                }
        }
 
@@ -1613,25 +1859,19 @@ static char *cli_prompt(EditLine *el)
                                        }
 
                                        /* If the color has been reset correctly, then there's no need to reset it later */
-                                       if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
-                                               color_used = 0;
-                                       } else {
-                                               color_used = 1;
-                                       }
+                                       color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
                                        break;
                                case 'd': /* date */
                                        memset(&tm, 0, sizeof(tm));
                                        time(&ts);
-                                       if (localtime_r(&ts, &tm)) {
+                                       if (localtime_r(&ts, &tm)) 
                                                strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
-                                       }
                                        break;
                                case 'h': /* hostname */
-                                       if (!gethostname(hostname, sizeof(hostname) - 1)) {
+                                       if (!gethostname(hostname, sizeof(hostname) - 1))
                                                strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
-                                       } else {
+                                       else
                                                strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
-                                       }
                                        break;
                                case 'H': /* short hostname */
                                        if (!gethostname(hostname, sizeof(hostname) - 1)) {
@@ -1642,9 +1882,8 @@ static char *cli_prompt(EditLine *el)
                                                        }
                                                }
                                                strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
-                                       } else {
+                                       } else
                                                strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
-                                       }
                                        break;
 #ifdef linux
                                case 'l': /* load avg */
@@ -1682,16 +1921,14 @@ static char *cli_prompt(EditLine *el)
                                case 't': /* time */
                                        memset(&tm, 0, sizeof(tm));
                                        time(&ts);
-                                       if (localtime_r(&ts, &tm)) {
+                                       if (localtime_r(&ts, &tm))
                                                strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
-                                       }
                                        break;
                                case '#': /* process console or remote? */
-                                       if (!ast_opt_remote) {
+                                       if (!ast_opt_remote) 
                                                strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
-                                       } else {
+                                       else
                                                strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
-                                       }
                                        break;
                                case '%': /* literal % */
                                        strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
@@ -1700,9 +1937,8 @@ static char *cli_prompt(EditLine *el)
                                        t--;
                                        break;
                                }
-                               while (*p != '\0') {
+                               while (*p != '\0')
                                        p++;
-                               }
                                t++;
                        } else {
                                *p = *t;
@@ -1713,11 +1949,10 @@ static char *cli_prompt(EditLine *el)
                if (color_used) {
                        /* Force colors back to normal at end */
                        term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
-                       if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
+                       if (strlen(term_code) > sizeof(prompt) - strlen(prompt))
                                strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
-                       } else {
+                       else
                                strncat(p, term_code, sizeof(term_code));
-                       }
                }
        } else if (remotehostname)
                snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
@@ -1801,7 +2036,7 @@ static int ast_cli_display_match_list(char **matches, int len, int max)
                        /* Don't print dupes */
                        if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
                                i--;
-                               free(matches[idx]);
+                               ast_free(matches[idx]);
                                matches[idx] = NULL;
                                continue;
                        }
@@ -1809,7 +2044,7 @@ static int ast_cli_display_match_list(char **matches, int len, int max)
                        numoutput++;
                        numoutputline++;
                        fprintf(stdout, "%-*s  ", max, matches[idx]);
-                       free(matches[idx]);
+                       ast_free(matches[idx]);
                        matches[idx] = NULL;
                }
                if (numoutputline > 0)
@@ -1878,7 +2113,7 @@ static char *cli_complete(EditLine *el, int ch)
                        mbuf[mlen] = '\0';
 
                        matches = ast_el_strtoarr(mbuf);
-                       free(mbuf);
+                       ast_free(mbuf);
                } else
                        matches = (char **) NULL;
        } else {
@@ -1923,7 +2158,9 @@ static char *cli_complete(EditLine *el, int ch)
                                retval = CC_REFRESH;
                        }
                }
-               free(matches);
+               for (i = 0; matches[i]; i++)
+                       ast_free(matches[i]);
+               ast_free(matches);
        }
 
        return (char *)(long)retval;
@@ -2041,10 +2278,14 @@ static void ast_remotecontrol(char * data)
                pid = atoi(cpid);
        else
                pid = -1;
-       snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
+       snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
        fdprint(ast_consock, tmp);
-       snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
+       snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
        fdprint(ast_consock, tmp);
+#if defined(MARKO_BDAY)
+       snprintf(tmp, sizeof(tmp), "marko show birthday");
+       fdprint(ast_consock, tmp);
+#endif
        if (ast_opt_mute) {
                snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
                fdprint(ast_consock, tmp);
@@ -2096,7 +2337,7 @@ static int show_version(void)
 }
 
 static int show_cli_help(void) {
-       printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
+       printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2007, Digium, Inc. and others.\n");
        printf("Usage: asterisk [OPTIONS]\n");
        printf("Valid Options:\n");
        printf("   -V              Display version number and exit\n");
@@ -2134,14 +2375,14 @@ static void ast_readconfig(void)
        struct ast_config *cfg;
        struct ast_variable *v;
        char *config = AST_CONFIG_FILE;
+       char hostname[MAXHOSTNAMELEN] = "";
 
        if (ast_opt_override_config) {
                cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
                if (!cfg)
                        ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
-       } else {
+       } else 
                cfg = ast_config_load(config);
-       }
 
        /* init with buildtime config */
        ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
@@ -2164,15 +2405,14 @@ static void ast_readconfig(void)
        }
 
        for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
-               if (!strcasecmp(v->name, "astctlpermissions")) {
+               if (!strcasecmp(v->name, "astctlpermissions"))
                        ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
-               } else if (!strcasecmp(v->name, "astctlowner")) {
+               else if (!strcasecmp(v->name, "astctlowner"))
                        ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
-               } else if (!strcasecmp(v->name, "astctlgroup")) {
+               else if (!strcasecmp(v->name, "astctlgroup"))
                        ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
-               } else if (!strcasecmp(v->name, "astctl")) {
+               else if (!strcasecmp(v->name, "astctl"))
                        ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
-               }
        }
 
        for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
@@ -2273,6 +2513,10 @@ static void ast_readconfig(void)
                        } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
                                option_maxload = 0.0;
                        }
+               /* Set the maximum amount of open files */
+               } else if (!strcasecmp(v->name, "maxfiles")) {
+                       option_maxfiles = atoi(v->value);
+                       set_ulimit(option_maxfiles);
                /* What user to run as */
                } else if (!strcasecmp(v->name, "runuser")) {
                        ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
@@ -2281,13 +2525,52 @@ static void ast_readconfig(void)
                        ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
                } else if (!strcasecmp(v->name, "systemname")) {
                        ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
+               } else if (!strcasecmp(v->name, "autosystemname")) {
+                       if (ast_true(v->value)) {
+                               if (!gethostname(hostname, sizeof(hostname) - 1))
+                                       ast_copy_string(ast_config_AST_SYSTEM_NAME, hostname, sizeof(ast_config_AST_SYSTEM_NAME));
+                               else {
+                                       if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
+                                               ast_copy_string(ast_config_AST_SYSTEM_NAME, "localhost", sizeof(ast_config_AST_SYSTEM_NAME));
+                                       }
+                                       ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
+                               }
+                       }
                } else if (!strcasecmp(v->name, "languageprefix")) {
                        ast_language_is_prefix = ast_true(v->value);
+#if defined(HAVE_SYSINFO)
+               } else if (!strcasecmp(v->name, "minmemfree")) {
+                       /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
+                        * if the amount of free memory falls below this watermark */
+                       if ((sscanf(v->value, "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
+                               option_minmemfree = 0;
+                       }
+#endif
                }
        }
        ast_config_destroy(cfg);
 }
 
+static void *monitor_sig_flags(void *unused)
+{
+       for (;;) {
+               struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
+               int a;
+               poll(&p, 1, -1);
+               if (sig_flags.need_reload) {
+                       sig_flags.need_reload = 0;
+                       ast_module_reload(NULL);
+               }
+               if (sig_flags.need_quit) {
+                       sig_flags.need_quit = 0;
+                       quit_handler(0, 0, 1, 0);
+               }
+               read(sig_alert_pipe[0], &a, sizeof(a));
+       }
+
+       return NULL;
+}
+
 int main(int argc, char *argv[])
 {
        int c;
@@ -2323,6 +2606,7 @@ int main(int argc, char *argv[])
        ast_alaw_init();
        callerid_init();
        ast_builtins_init();
+       ast_event_init();
        ast_utils_init();
        tdd_init();
        /* When Asterisk restarts after it has dropped the root privileges,
@@ -2333,8 +2617,15 @@ int main(int argc, char *argv[])
        if (getenv("HOME")) 
                snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
        /* Check for options */
-       while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
+       while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:")) != -1) {
                switch (c) {
+#if defined(HAVE_SYSINFO)
+               case 'e':
+                       if ((sscanf(&optarg[1], "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
+                               option_minmemfree = 0;
+                       }
+                       break;
+#endif
 #if HAVE_WORKING_FORK
                case 'F':
                        ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
@@ -2447,6 +2738,9 @@ int main(int argc, char *argv[])
                ast_verbose("[ Reading Master Configuration ]\n");
        ast_readconfig();
 
+       if (!ast_language_is_prefix && !ast_opt_remote)
+               ast_log(LOG_WARNING, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n");
+
        if (ast_opt_dump_core) {
                struct rlimit l;
                memset(&l, 0, sizeof(l));
@@ -2487,12 +2781,21 @@ int main(int argc, char *argv[])
        }
 
        if (!is_child_of_nonroot && runuser) {
+#ifdef HAVE_CAP
+               int has_cap = 1;
+#endif /* HAVE_CAP */
                struct passwd *pw;
                pw = getpwnam(runuser);
                if (!pw) {
                        ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
                        exit(1);
                }
+#ifdef HAVE_CAP
+               if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
+                       ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
+                       has_cap = 0;
+               }
+#endif /* HAVE_CAP */
                if (!rungroup) {
                        if (setgid(pw->pw_gid)) {
                                ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
@@ -2510,6 +2813,19 @@ int main(int argc, char *argv[])
                setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
                if (option_verbose)
                        ast_verbose("Running as user '%s'\n", runuser);
+#ifdef HAVE_CAP
+               if (has_cap) {
+                       cap_t cap;
+
+                       cap = cap_from_text("cap_net_admin=ep");
+
+                       if (cap_set_proc(cap))
+                               ast_log(LOG_WARNING, "Unable to install capabilities.\n");
+
+                       if (cap_free(cap))
+                               ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
+               }
+#endif /* HAVE_CAP */
        }
 
 #endif /* __CYGWIN__ */
@@ -2522,7 +2838,7 @@ int main(int argc, char *argv[])
        }
 #endif
 
-       term_init();
+       ast_term_init();
        printf(term_end());
        fflush(stdout);
 
@@ -2611,21 +2927,24 @@ int main(int argc, char *argv[])
        srand((unsigned int) getpid() + (unsigned int) time(NULL));
        initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
 
-       if (init_logger()) {
+       if (init_logger()) {            /* Start logging subsystem */
                printf(term_quit());
                exit(1);
        }
-       if (load_modules(1)) {
+
+       threadstorage_init();
+
+       if (load_modules(1)) {          /* Load modules, pre-load only */
                printf(term_quit());
                exit(1);
        }
 
-       if (dnsmgr_init()) {
+       if (dnsmgr_init()) {            /* Initialize the DNS manager */
                printf(term_quit());
                exit(1);
        }
 
-       ast_http_init();
+       ast_http_init();                /* Start the HTTP server, if needed */
 
        ast_channels_init();
 
@@ -2694,6 +3013,9 @@ int main(int argc, char *argv[])
        if (ast_opt_no_fork)
                consolethread = pthread_self();
 
+       if (pipe(sig_alert_pipe))
+               sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
+
        ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
        pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
 
@@ -2702,12 +3024,16 @@ int main(int argc, char *argv[])
 #endif 
 
        time(&ast_startuptime);
-       ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
+       ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
 
        if (ast_opt_console) {
                /* Console stuff now... */
                /* Register our quit function */
                char title[256];
+               pthread_t dont_care;
+
+               ast_pthread_create_detached(&dont_care, NULL, monitor_sig_flags, NULL);
+
                set_icon("Asterisk");
                snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
                set_title(title);
@@ -2719,29 +3045,22 @@ int main(int argc, char *argv[])
                                        buf[strlen(buf)-1] = '\0';
 
                                consolehandler((char *)buf);
-                       } else {
-                               if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
-                                         strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
-                                       /* Whoa, stdout disappeared from under us... Make /dev/null's */
-                                       int fd;
-                                       fd = open("/dev/null", O_RDWR);
-                                       if (fd > -1) {
-                                               dup2(fd, STDOUT_FILENO);
-                                               dup2(fd, STDIN_FILENO);
-                                       } else
-                                               ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
-                                       break;
-                               }
+                       } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
+                                  strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
+                               /* Whoa, stdout disappeared from under us... Make /dev/null's */
+                               int fd;
+                               fd = open("/dev/null", O_RDWR);
+                               if (fd > -1) {
+                                       dup2(fd, STDOUT_FILENO);
+                                       dup2(fd, STDIN_FILENO);
+                               } else
+                                       ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
+                               break;
                        }
                }
-
        }
-       /* Do nothing */
-       for (;;) {      /* apparently needed for Mac OS X */
-               struct pollfd p = { -1 /* no descriptor */, 0, 0 };
 
-               poll(&p, 0, -1);
-       }
+       monitor_sig_flags(NULL);
 
        return 0;
 }