Skip to content
Snippets Groups Projects
asterisk.c 136 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    /*
    
     * Asterisk -- An open source telephony toolkit.
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * Copyright (C) 1999 - 2014, Digium, Inc.
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * Mark Spencer <markster@digium.com>
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * See http://www.asterisk.org for more information about
     * the Asterisk project. Please do not directly contact
     * any of the maintainers of this project for assistance;
     * the project provides a web site, mailing lists and IRC
     * channels for your use.
     *
    
    Mark Spencer's avatar
    Mark Spencer committed
     * This program is free software, distributed under the terms of
    
     * the GNU General Public License Version 2. See the LICENSE file
     * at the top of the source tree.
     */
    
    
    
    /* Doxygenified Copyright Header */
    /*!
    
     * \mainpage Asterisk -- The Open Source Telephony Project
    
     * \par Welcome
     *
     * This documentation created by the Doxygen project clearly explains the
     * internals of the Asterisk software. This documentation contains basic
     * examples, developer documentation, support information, and information
     * for upgrading.
    
    Andrew Latham's avatar
    Andrew Latham committed
     * \section community Community
     * Asterisk is a big project and has a busy community. Look at the
     * resources for questions and stick around to help answer questions.
     * \li \ref asterisk_community_resources
     *
    
     * \par Developer Documentation for Asterisk
    
     * This is the main developer documentation for Asterisk. It is
     * generated by running "make progdocs" from the Asterisk source tree.
    
     * In addition to the information available on the Asterisk source code,
     * please see the appendices for information on coding guidelines,
    
     * release management, commit policies, and more.
     *
    
     * \par Additional documentation
    
     * \arg \ref DevDoc
    
    Andrew Latham's avatar
    Andrew Latham committed
     * \arg \ref configuration_file
    
     * \arg \ref channel_drivers
     * \arg \ref applications
    
     * \section copyright Copyright and Author
    
     * Copyright (C) 1999 - 2014, Digium, Inc.
    
     * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
    
     * of <a rel="nofollow" href="http://www.digium.com">Digium, Inc</a>.
    
     *
     * \author Mark Spencer <markster@digium.com>
     *
     * See http://www.asterisk.org for more information about
     * the Asterisk project. Please do not directly contact
     * any of the maintainers of this project for assistance;
    
     * the project provides a web site, mailing lists, and IRC
    
     * channels for your use.
    
    Andrew Latham's avatar
    Andrew Latham committed
     */
    
    /*!
     * \page asterisk_community_resources Asterisk Community Resources
     * \par Websites
     * \li http://www.asterisk.org Asterisk Homepage
     * \li http://wiki.asterisk.org Asterisk Wiki
     *
     * \par Mailing Lists
     * \par
     * All lists: http://lists.digium.com/mailman/listinfo
     * \li aadk-commits	SVN commits to the AADK repository
     * \li asterisk-addons-commits	SVN commits to the Asterisk addons project
     * \li asterisk-announce	[no description available]
     * \li asterisk-biz	Commercial and Business-Oriented Asterisk Discussion
     * \li Asterisk-BSD	Asterisk on BSD discussion
     * \li asterisk-bugs	[no description available]
     * \li asterisk-commits	SVN commits to the Asterisk project
     * \li asterisk-dev	Asterisk Developers Mailing List
     * \li asterisk-doc	Discussions regarding The Asterisk Documentation Project
     * \li asterisk-embedded	Asterisk Embedded Development
     * \li asterisk-gui	Asterisk GUI project discussion
     * \li asterisk-gui-commits	SVN commits to the Asterisk-GUI project
     * \li asterisk-ha-clustering	Asterisk High Availability and Clustering List - Non-Commercial Discussion
     * \li Asterisk-i18n	Discussion of Asterisk internationalization
     * \li asterisk-r2	[no description available]
     * \li asterisk-scf-commits	Commits to the Asterisk SCF project code repositories
     * \li asterisk-scf-committee	Asterisk SCF Steering Committee discussions
     * \li asterisk-scf-dev	Asterisk SCF Developers Mailing List
     * \li asterisk-scf-wiki-changes	Changes to the Asterisk SCF space on wiki.asterisk.org
     * \li asterisk-security	Asterisk Security Discussion
     * \li asterisk-speech-rec	Use of speech recognition in Asterisk
     * \li asterisk-ss7	[no description available]
     * \li asterisk-users	Asterisk Users Mailing List - Non-Commercial Discussion
     * \li asterisk-video	Development discussion of video media support in Asterisk
     * \li asterisk-wiki-changes	Changes to the Asterisk space on wiki.asterisk.org
     * \li asterisknow	AsteriskNOW Discussion
     * \li dahdi-commits	SVN commits to the DAHDI project
     * \li digium-announce	Digium Product Announcements
     * \li Dundi	Distributed Universal Number Discovery
     * \li libiax2-commits	SVN commits to the libiax2 project
     * \li libpri-commits	SVN commits to the libpri project
     * \li libss7-commits	SVN commits to the libss7 project
     * \li svn-commits	SVN commits to the Digium repositories
     * \li Test-results	Results from automated testing
     * \li thirdparty-commits	SVN commits to the Digium third-party software repository
     * \li zaptel-commits	SVN commits to the Zaptel project
     *
     * \par Forums
     * \li Forums are located at http://forums.asterisk.org/
     *
     * \par IRC
     * \par
     * Use http://www.freenode.net IRC server to connect with Asterisk
     * developers and users in realtime.
    
    Andrew Latham's avatar
    Andrew Latham committed
     * \li \verbatim #asterisk \endverbatim Asterisk Users Room
     * \li \verbatim #asterisk-dev \endverbatim Asterisk Developers Room
     *
     * \par More
     * \par
     * If you would like to add a resource to this list please create an issue
     * on the issue tracker with a patch.
    
     * \brief Top level source file for Asterisk - the Open Source PBX.
     *	Implementation of PBX core functions and CLI interface.
    
    /*! \li \ref asterisk.c uses the configuration file \ref asterisk.conf
    
    Andrew Latham's avatar
    Andrew Latham committed
     * \addtogroup configuration_file
     */
    
    /*! \page asterisk.conf asterisk.conf
     * \verbinclude asterisk.conf.sample
     */
    
    
    /*** MODULEINFO
    	<support_level>core</support_level>
     ***/
    
    
    #include "asterisk.h"
    
    ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
    
    
    #undef sched_setscheduler
    #undef setpriority
    
    #include <fcntl.h>
    #include <signal.h>
    #include <sched.h>
    #include <sys/un.h>
    #include <sys/wait.h>
    #include <ctype.h>
    #include <sys/resource.h>
    #include <grp.h>
    #include <pwd.h>
    #include <sys/stat.h>
    
    #elif defined(HAVE_SYSCTL)
    #include <sys/param.h>
    #include <sys/sysctl.h>
    
    #include <sys/vmmeter.h>
    #if defined(__FreeBSD__)
    #include <vm/vm_param.h>
    #endif
    
    #if defined(HAVE_SWAPCTL)
    
    #include <regex.h>
    
    #if defined(SOLARIS)
    
    int daemon(int, int);  /* defined in libresolv of all places */
    
    #include <sys/loadavg.h>
    
    #ifdef linux
    #include <sys/prctl.h>
    #ifdef HAVE_CAP
    #include <sys/capability.h>
    #endif /* HAVE_CAP */
    #endif /* linux */
    
    
    /* we define here the variables so to better agree on the prototype */
    #include "asterisk/paths.h"
    
    #include "asterisk/network.h"
    
    #include "asterisk/cli.h"
    #include "asterisk/channel.h"
    
    #include "asterisk/translate.h"
    
    #include "asterisk/features.h"
    
    #include "asterisk/ulaw.h"
    #include "asterisk/alaw.h"
    #include "asterisk/callerid.h"
    #include "asterisk/image.h"
    #include "asterisk/tdd.h"
    #include "asterisk/term.h"
    #include "asterisk/manager.h"
    
    #include "asterisk/cel.h"
    
    #include "asterisk/pbx.h"
    #include "asterisk/enum.h"
    
    #include "asterisk/udptl.h"
    
    #include "asterisk/app.h"
    #include "asterisk/lock.h"
    #include "asterisk/utils.h"
    #include "asterisk/file.h"
    #include "asterisk/io.h"
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include "editline/histedit.h"
    
    #include "asterisk/ast_version.h"
    
    #include "asterisk/linkedlists.h"
    
    #include "asterisk/presencestate.h"
    
    #include "asterisk/module.h"
    
    #include "asterisk/buildinfo.h"
    
    #include "asterisk/poll-compat.h"
    
    #include "asterisk/ccss.h"
    
    David Vossel's avatar
    David Vossel committed
    #include "asterisk/test.h"
    
    #include "asterisk/aoc.h"
    
    #include "asterisk/uuid.h"
    
    #include "asterisk/sorcery.h"
    
    Joshua Colp's avatar
    Joshua Colp committed
    #include "asterisk/bucket.h"
    
    #include "asterisk/stasis.h"
    
    #include "asterisk/json.h"
    
    #include "asterisk/stasis_endpoints.h"
    
    #include "asterisk/stasis_system.h"
    
    #include "asterisk/security_events.h"
    
    #include "asterisk/endpoints.h"
    
    #include "asterisk/codec.h"
    #include "asterisk/format_cache.h"
    
    #include "asterisk/astdb.h"
    
    #include "asterisk/options.h"
    
    	<managerEvent language="en_US" name="FullyBooted">
    		<managerEventInstance class="EVENT_FLAG_SYSTEM">
    			<synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
    			<syntax>
    				<parameter name="Status">
    					<para>Informational message</para>
    				</parameter>
    			</syntax>
    		</managerEventInstance>
    	</managerEvent>
    	<managerEvent language="en_US" name="Shutdown">
    		<managerEventInstance class="EVENT_FLAG_SYSTEM">
    			<synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
    			<syntax>
    				<parameter name="Shutdown">
    					<para>Whether the shutdown is proceeding cleanly (all channels
    					were hungup successfully) or uncleanly (channels will be
    					terminated)</para>
    					<enumlist>
    						<enum name="Uncleanly"/>
    						<enum name="Cleanly"/>
    					</enumlist>
    				</parameter>
    				<parameter name="Restart">
    					<para>Whether or not a restart will occur.</para>
    					<enumlist>
    						<enum name="True"/>
    						<enum name="False"/>
    					</enumlist>
    				</parameter>
    			</syntax>
    		</managerEventInstance>
    	</managerEvent>
    
    #ifndef AF_LOCAL
    #define AF_LOCAL AF_UNIX
    #define PF_LOCAL PF_UNIX
    #endif
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define AST_MAX_CONNECTS 128
    #define NUM_MSGS 64
    
    
    /*! Default minimum DTMF digit length - 80ms */
    #define AST_MIN_DTMF_DURATION 80
    
    
    
    /*! \brief Welcome message when starting a CLI interface */
    
    #define WELCOME_MESSAGE \
    
        ast_verbose("Asterisk %s, Copyright (C) 1999 - 2014, 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", ast_get_version()) \
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    
    /*! \defgroup main_options Main Configuration Options
    
    Russell Bryant's avatar
    Russell Bryant committed
     * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
     * \arg \ref Config_ast "asterisk.conf"
    
     * \note Some of them can be changed in the CLI
    
    struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
    
    /*! Maximum active system verbosity level. */
    int ast_verb_sys_level;
    
    
    int option_verbose;				/*!< Verbosity level */
    int option_debug;				/*!< Debug level */
    
    int ast_pjproject_max_log_level = -1;/* Default to -1 to know if we have read the level from pjproject yet. */
    
    int ast_option_pjproject_log_level;
    
    double ast_option_maxload;			/*!< Max load avg on system */
    int ast_option_maxcalls;			/*!< Max number of active calls */
    int ast_option_maxfiles;			/*!< Max number of open file handles (files, sockets) */
    
    unsigned int option_dtmfminduration;		/*!< Minimum duration of DTMF. */
    
    long option_minmemfree;				/*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
    
    unsigned int ast_option_rtpptdynamic;
    
    struct ast_eid ast_eid_default;
    
    /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
    char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
    
    static int ast_socket = -1;		/*!< UNIX Socket for allowing remote control */
    static int ast_consock = -1;		/*!< UNIX Socket for controlling another asterisk */
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct console {
    
    	int fd;				/*!< File descriptor */
    	int p[2];			/*!< Pipe */
    	pthread_t t;			/*!< Thread of handler */
    
    	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;
    
    	AST_LIST_ENTRY(ast_atexit) list;
    
    static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
    
    struct timeval ast_startuptime;
    struct timeval ast_lastreloadtime;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    
    static History *el_hist;
    static EditLine *el;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char *remotehostname;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct console consoles[AST_MAX_CONNECTS];
    
    
    char ast_defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
    
    static int ast_el_add_history(const char *);
    static int ast_el_read_history(const char *);
    static int ast_el_write_history(const char *);
    
    static void ast_el_read_default_histfile(void);
    static void ast_el_write_default_histfile(void);
    
    static void asterisk_daemon(int isroot, const char *runuser, const char *rungroup);
    
    #define DEFAULT_MONITOR_DIR DEFAULT_SPOOL_DIR "/monitor"
    #define DEFAULT_RECORDING_DIR DEFAULT_SPOOL_DIR "/recording"
    
    
    struct _cfg_paths {
    	char config_dir[PATH_MAX];
    	char module_dir[PATH_MAX];
    	char spool_dir[PATH_MAX];
    	char monitor_dir[PATH_MAX];
    
    	char recording_dir[PATH_MAX];
    
    	char var_dir[PATH_MAX];
    	char data_dir[PATH_MAX];
    	char log_dir[PATH_MAX];
    	char agi_dir[PATH_MAX];
    	char run_dir[PATH_MAX];
    	char key_dir[PATH_MAX];
    
    	char config_file[PATH_MAX];
    	char db_path[PATH_MAX];
    
    	char sbin_dir[PATH_MAX];
    
    	char pid_path[PATH_MAX];
    	char socket_path[PATH_MAX];
    	char run_user[PATH_MAX];
    	char run_group[PATH_MAX];
    	char system_name[128];
    };
    
    static struct _cfg_paths cfg_paths;
    
    const char *ast_config_AST_CONFIG_DIR	= cfg_paths.config_dir;
    const char *ast_config_AST_CONFIG_FILE	= cfg_paths.config_file;
    const char *ast_config_AST_MODULE_DIR	= cfg_paths.module_dir;
    const char *ast_config_AST_SPOOL_DIR	= cfg_paths.spool_dir;
    const char *ast_config_AST_MONITOR_DIR	= cfg_paths.monitor_dir;
    
    const char *ast_config_AST_RECORDING_DIR	= cfg_paths.recording_dir;
    
    const char *ast_config_AST_VAR_DIR	= cfg_paths.var_dir;
    const char *ast_config_AST_DATA_DIR	= cfg_paths.data_dir;
    const char *ast_config_AST_LOG_DIR	= cfg_paths.log_dir;
    const char *ast_config_AST_AGI_DIR	= cfg_paths.agi_dir;
    const char *ast_config_AST_KEY_DIR	= cfg_paths.key_dir;
    const char *ast_config_AST_RUN_DIR	= cfg_paths.run_dir;
    
    const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
    
    
    const char *ast_config_AST_DB		= cfg_paths.db_path;
    const char *ast_config_AST_PID		= cfg_paths.pid_path;
    const char *ast_config_AST_SOCKET	= cfg_paths.socket_path;
    const char *ast_config_AST_RUN_USER	= cfg_paths.run_user;
    const char *ast_config_AST_RUN_GROUP	= cfg_paths.run_group;
    const char *ast_config_AST_SYSTEM_NAME	= cfg_paths.system_name;
    
    static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
    static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
    static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
    static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
    
    extern unsigned int ast_FD_SETSIZE;
    
    
    	/*! Normal operation */
    	NOT_SHUTTING_DOWN,
    	/*! Committed to shutting down.  Final phase */
    	SHUTTING_DOWN_FINAL,
    	/*! Committed to shutting down.  Initial phase */
    	SHUTTING_DOWN,
    	/*!
    	 * Valid values for quit_handler() niceness below.
    	 * These shutdown/restart levels can be cancelled.
    	 *
    	 * Remote console exit right now
    	 */
    
    	/*! core stop/restart now */
    
    	/*! core stop/restart gracefully */
    
    	/*! core stop/restart when convenient */
    
    	SHUTDOWN_REALLY_NICE
    } shutdown_nice_t;
    
    static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
    
    
    /*! Prevent new channel allocation for shutdown. */
    static int shutdown_pending;
    
    
    static int restartnow;
    
    static pthread_t consolethread = AST_PTHREADT_NULL;
    
    static pthread_t mon_sig_flags;
    
    static int canary_pid = 0;
    static char canary_filename[128];
    
    static char randompool[256];
    
    
    static int sig_alert_pipe[2] = { -1, -1 };
    static struct {
    	 unsigned int need_reload:1;
    	 unsigned int need_quit:1;
    
    	 unsigned int need_quit_handler:1;
    
    #if !defined(LOW_MEMORY)
    
    struct registered_file {
    	AST_RWLIST_ENTRY(registered_file) list;
    
    static AST_RWLIST_HEAD_STATIC(registered_files, registered_file);
    
    
    void ast_register_file_version(const char *file, const char *version)
    {
    
    	struct registered_file *reg;
    
    	reg = ast_calloc(1, sizeof(*reg));
    	if (!reg) {
    
    	reg->file = file;
    	AST_RWLIST_WRLOCK(&registered_files);
    	AST_RWLIST_INSERT_HEAD(&registered_files, reg, list);
    	AST_RWLIST_UNLOCK(&registered_files);
    
    }
    
    void ast_unregister_file_version(const char *file)
    {
    
    	struct registered_file *find;
    
    	AST_RWLIST_WRLOCK(&registered_files);
    	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&registered_files, find, list) {
    
    		if (!strcasecmp(find->file, file)) {
    
    			AST_RWLIST_REMOVE_CURRENT(list);
    
    	AST_RWLIST_TRAVERSE_SAFE_END;
    
    	AST_RWLIST_UNLOCK(&registered_files);
    
    char *ast_complete_source_filename(const char *partial, int n)
    {
    
    	struct registered_file *find;
    
    	size_t len = strlen(partial);
    	int count = 0;
    	char *res = NULL;
    
    
    	AST_RWLIST_RDLOCK(&registered_files);
    	AST_RWLIST_TRAVERSE(&registered_files, find, list) {
    
    		if (!strncasecmp(find->file, partial, len) && ++count > n) {
    			res = ast_strdup(find->file);
    			break;
    		}
    	}
    
    	AST_RWLIST_UNLOCK(&registered_files);
    
    const char *ast_file_version_find(const char *file)
    {
    
    	struct registered_file *iterator;
    
    	AST_RWLIST_RDLOCK(&registered_files);
    	AST_RWLIST_TRAVERSE(&registered_files, iterator, list) {
    		if (!strcasecmp(iterator->file, file)) {
    
    		}
    	}
    	AST_RWLIST_UNLOCK(&registered_files);
    	if (iterator) {
    		return ast_get_version();
    
    struct thread_list_t {
    
    	AST_RWLIST_ENTRY(thread_list_t) list;
    
    	char *name;
    	pthread_t id;
    
    static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
    
    
    void ast_register_thread(char *name)
    
    	struct thread_list_t *new = ast_calloc(1, sizeof(*new));
    
    	if (!new)
    		return;
    
    	new->id = pthread_self();
    
    	new->name = name; /* steal the allocated memory for the thread name */
    
    	AST_RWLIST_WRLOCK(&thread_list);
    	AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
    	AST_RWLIST_UNLOCK(&thread_list);
    
    }
    
    void ast_unregister_thread(void *id)
    {
    	struct thread_list_t *x;
    
    
    	AST_RWLIST_WRLOCK(&thread_list);
    	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
    
    		if ((void *) x->id == id) {
    
    			AST_RWLIST_REMOVE_CURRENT(list);
    
    	AST_RWLIST_TRAVERSE_SAFE_END;
    	AST_RWLIST_UNLOCK(&thread_list);
    
    /*! \brief Give an overview of core settings */
    
    static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    	char pbx_uuid[AST_UUID_STR_LEN];
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "core show settings";
    		e->usage = "Usage: core show settings\n"
    			   "       Show core misc settings";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    
    	ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
    
    	ast_pbx_uuid_get(pbx_uuid, sizeof(pbx_uuid));
    
    	ast_cli(a->fd, "\nPBX Core settings\n");
    	ast_cli(a->fd, "-----------------\n");
    
    	ast_cli(a->fd, "  Version:                     %s\n", ast_get_version());
    
    	ast_cli(a->fd, "  Build Options:               %s\n", S_OR(ast_get_build_opts(), "(none)"));
    
    	if (ast_option_maxcalls)
    		ast_cli(a->fd, "  Maximum calls:               %d (Current %d)\n", ast_option_maxcalls, ast_active_channels());
    
    		ast_cli(a->fd, "  Maximum calls:               Not set\n");
    
    
    	if (getrlimit(RLIMIT_NOFILE, &limits)) {
    		ast_cli(a->fd, "  Maximum open file handles:   Error because of %s\n", strerror(errno));
    	} else if (limits.rlim_cur == RLIM_INFINITY) {
    		ast_cli(a->fd, "  Maximum open file handles:   Unlimited\n");
    	} else if (limits.rlim_cur < ast_option_maxfiles) {
    		ast_cli(a->fd, "  Maximum open file handles:   %d (is) %d (requested)\n", (int) limits.rlim_cur, ast_option_maxfiles);
    	} else {
    		ast_cli(a->fd, "  Maximum open file handles:   %d\n", (int) limits.rlim_cur);
    	}
    
    
    	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);
    
    	ast_cli(a->fd, "  Minimum free memory:         %ld MB\n", option_minmemfree);
    
    	if (ast_localtime(&ast_startuptime, &tm, NULL)) {
    
    		ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
    
    		ast_cli(a->fd, "  Startup time:                %s\n", buf);
    
    	if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
    
    		ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
    
    		ast_cli(a->fd, "  Last reload time:            %s\n", buf);
    
    	ast_cli(a->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(a->fd, "  System name:                 %s\n", ast_config_AST_SYSTEM_NAME);
    
    	ast_cli(a->fd, "  Entity ID:                   %s\n", eid_str);
    
    	ast_cli(a->fd, "  PBX UUID:                    %s\n", pbx_uuid);
    
    	ast_cli(a->fd, "  Default language:            %s\n", ast_defaultlanguage);
    
    	ast_cli(a->fd, "  Language prefix:             %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
    	ast_cli(a->fd, "  User name and group:         %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
    	ast_cli(a->fd, "  Executable includes:         %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
    	ast_cli(a->fd, "  Transcode via SLIN:          %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
    
    	ast_cli(a->fd, "  Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
    
    	ast_cli(a->fd, "  Generic PLC:                 %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
    
    	ast_cli(a->fd, "  Min DTMF duration::          %u\n", option_dtmfminduration);
    
    #if !defined(LOW_MEMORY)
    	ast_cli(a->fd, "  Cache media frames:          %s\n", ast_opt_cache_media_frames ? "Enabled" : "Disabled");
    #endif
    
    	if (ast_option_rtpptdynamic == AST_RTP_PT_LAST_REASSIGN) {
    		ast_cli(a->fd, "  RTP dynamic payload types:   %u,%u-%u\n",
    		        ast_option_rtpptdynamic,
    		        AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT - 1);
    	} else if (ast_option_rtpptdynamic < AST_RTP_PT_LAST_REASSIGN) {
    		ast_cli(a->fd, "  RTP dynamic payload types:   %u-%u,%u-%u\n",
    		        ast_option_rtpptdynamic, AST_RTP_PT_LAST_REASSIGN,
    		        AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT - 1);
    	} else {
    		ast_cli(a->fd, "  RTP dynamic payload types:   %u-%u\n",
    		        AST_RTP_PT_FIRST_DYNAMIC, AST_RTP_MAX_PT - 1);
    	}
    
    
    	ast_cli(a->fd, "\n* Subsystems\n");
    	ast_cli(a->fd, "  -------------\n");
    	ast_cli(a->fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
    	ast_cli(a->fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
    
    	ast_cli(a->fd, "  Call data records:           %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
    
    	ast_cli(a->fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
    
    
    	/*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */
    
    
    	ast_cli(a->fd, "\n* Directories\n");
    	ast_cli(a->fd, "  -------------\n");
    	ast_cli(a->fd, "  Configuration file:          %s\n", ast_config_AST_CONFIG_FILE);
    	ast_cli(a->fd, "  Configuration directory:     %s\n", ast_config_AST_CONFIG_DIR);
    	ast_cli(a->fd, "  Module directory:            %s\n", ast_config_AST_MODULE_DIR);
    	ast_cli(a->fd, "  Spool directory:             %s\n", ast_config_AST_SPOOL_DIR);
    	ast_cli(a->fd, "  Log directory:               %s\n", ast_config_AST_LOG_DIR);
    
    	ast_cli(a->fd, "  Run/Sockets directory:       %s\n", ast_config_AST_RUN_DIR);
    	ast_cli(a->fd, "  PID file:                    %s\n", ast_config_AST_PID);
    	ast_cli(a->fd, "  VarLib directory:            %s\n", ast_config_AST_VAR_DIR);
    	ast_cli(a->fd, "  Data directory:              %s\n", ast_config_AST_DATA_DIR);
    	ast_cli(a->fd, "  ASTDB:                       %s\n", ast_config_AST_DB);
    	ast_cli(a->fd, "  IAX2 Keys directory:         %s\n", ast_config_AST_KEY_DIR);
    	ast_cli(a->fd, "  AGI Scripts directory:       %s\n", ast_config_AST_AGI_DIR);
    
    	ast_cli(a->fd, "\n\n");
    	return CLI_SUCCESS;
    
    static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    {
    	int count = 0;
    	struct thread_list_t *cur;
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "core show threads";
    
    		e->usage =
    
    			"Usage: core show threads\n"
    			"       List threads currently active in the system.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	AST_RWLIST_RDLOCK(&thread_list);
    	AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
    
    		ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
    
    	AST_RWLIST_UNLOCK(&thread_list);
    
    	ast_cli(a->fd, "%d threads listed.\n", count);
    	return CLI_SUCCESS;
    
    #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
    /*
     * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
     * to be based on the new swapctl(2) system call.
     */
    static int swapmode(int *used, int *total)
    {
    	struct swapent *swdev;
    	int nswap, rnswap, i;
    
    	nswap = swapctl(SWAP_NSWAP, 0, 0);
    	if (nswap == 0)
    		return 0;
    
    	swdev = ast_calloc(nswap, sizeof(*swdev));
    	if (swdev == NULL)
    		return 0;
    
    	rnswap = swapctl(SWAP_STATS, swdev, nswap);
    	if (rnswap == -1) {
    		ast_free(swdev);
    		return 0;
    	}
    
    	/* if rnswap != nswap, then what? */
    
    	/* Total things up */
    	*total = *used = 0;
    	for (i = 0; i < nswap; i++) {
    		if (swdev[i].se_flags & SWF_ENABLE) {
    			*used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
    			*total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
    		}
    	}
    	ast_free(swdev);
    	return 1;
    }
    
    #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
    
    	*used = *total = 0;
    
    #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
    
    /*! \brief Give an overview of system statistics */
    
    static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    	int totalswap = 0;
    
    #elif defined(HAVE_SYSCTL)
    	static int pageshift;
    	struct vmtotal vmtotal;
    	struct timeval	boottime;
    	time_t	now;
    	int mib[2], pagesize, usedswap = 0;
    	size_t len;
    #endif
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "core show sysinfo";
    		e->usage =
    			"Usage: core show sysinfo\n"
    			"       List current system information.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    #if defined(HAVE_SYSINFO)
    
    	physmem = sys_info.totalram * sys_info.mem_unit;
    	freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
    	totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
    	freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
    
    	nprocs = sys_info.procs;
    
    #elif defined(HAVE_SYSCTL)
    	/* calculate the uptime by looking at boottime */
    	time(&now);
    	mib[0] = CTL_KERN;
    	mib[1] = KERN_BOOTTIME;
    	len = sizeof(boottime);
    	if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
    		uptime = now - boottime.tv_sec;
    	}
    	uptime = uptime/3600;
    	/* grab total physical memory  */
    	mib[0] = CTL_HW;
    
    #if defined(HW_PHYSMEM64)
    
    #else
    	mib[1] = HW_PHYSMEM;
    #endif
    
    	len = sizeof(physmem);
    	sysctl(mib, 2, &physmem, &len, NULL, 0);
    
    	pagesize = getpagesize();
    	pageshift = 0;
    	while (pagesize > 1) {
    		pageshift++;
    		pagesize >>= 1;
    	}
    
    	/* we only need the amount of log(2)1024 for our conversion */
    	pageshift -= 10;
    
    	/* grab vm totals */
    	mib[0] = CTL_VM;
    	mib[1] = VM_METER;
    	len = sizeof(vmtotal);
    	sysctl(mib, 2, &vmtotal, &len, NULL, 0);
    	freeram = (vmtotal.t_free << pageshift);
    	/* generate swap usage and totals */
    
    	freeswap = (totalswap - usedswap);
    	/* grab number of processes */
    
    #if defined(__OpenBSD__)
    
    	mib[0] = CTL_KERN;
    	mib[1] = KERN_NPROCS;
    	len = sizeof(nprocs);
    	sysctl(mib, 2, &nprocs, &len, NULL, 0);
    
    	ast_cli(a->fd, "\nSystem Statistics\n");
    	ast_cli(a->fd, "-----------------\n");
    
    	ast_cli(a->fd, "  System Uptime:             %ld hours\n", uptime);
    
    	ast_cli(a->fd, "  Total RAM:                 %" PRIu64 " KiB\n", physmem / 1024);
    	ast_cli(a->fd, "  Free RAM:                  %" PRIu64 " KiB\n", freeram);
    
    	ast_cli(a->fd, "  Buffer RAM:                %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
    
    #if defined(HAVE_SWAPCTL) || defined(HAVE_SYSINFO)
    
    	ast_cli(a->fd, "  Total Swap Space:          %d KiB\n", totalswap);
    
    	ast_cli(a->fd, "  Free Swap Space:           %" PRIu64 " KiB\n\n", freeswap);
    
    	ast_cli(a->fd, "  Number of Processes:       %d \n\n", nprocs);
    
    struct profile_entry {
    	const char *name;
    	uint64_t	scale;	/* if non-zero, values are scaled by this */
    	int64_t	mark;
    	int64_t	value;
    	int64_t	events;
    };
    
    struct profile_data {
    	int entries;
    	int max_size;
    	struct profile_entry e[0];
    };
    
    static struct profile_data *prof_data;
    
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief allocates a counter with a given name and scale.
     * \return Returns the identifier of the counter.
    
     */
    int ast_add_profile(const char *name, uint64_t scale)
    {
    	int l = sizeof(struct profile_data);
    	int n = 10;	/* default entries */
    
    	if (prof_data == NULL) {
    		prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
    		if (prof_data == NULL)
    			return -1;
    		prof_data->entries = 0;
    		prof_data->max_size = n;
    	}
    	if (prof_data->entries >= prof_data->max_size) {
    		void *p;
    		n = prof_data->max_size + 20;
    		p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
    		if (p == NULL)
    			return -1;
    		prof_data = p;
    		prof_data->max_size = n;
    	}
    	n = prof_data->entries++;
    	prof_data->e[n].name = ast_strdup(name);
    	prof_data->e[n].value = 0;
    	prof_data->e[n].events = 0;
    	prof_data->e[n].mark = 0;
    	prof_data->e[n].scale = scale;
    	return n;
    }
    
    int64_t ast_profile(int i, int64_t delta)
    {
    	if (!prof_data || i < 0 || i > prof_data->entries)	/* invalid index */
    		return 0;
    	if (prof_data->e[i].scale > 1)
    		delta /= prof_data->e[i].scale;
    	prof_data->e[i].value += delta;
    	prof_data->e[i].events++;
    	return prof_data->e[i].value;
    }
    
    
    /* The RDTSC instruction was introduced on the Pentium processor and is not
     * implemented on certain clones, like the Cyrix 586. Hence, the previous
     * expectation of __i386__ was in error. */
    #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
    
    #if defined(__FreeBSD__)
    #include <machine/cpufunc.h>
    #elif defined(linux)
    
    Jason Parker's avatar
    Jason Parker committed
    static __inline uint64_t
    
    	uint64_t rv;
    
    	__asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
    	return (rv);
    }
    #endif
    #else	/* supply a dummy function on other platforms */
    
    Jason Parker's avatar
    Jason Parker committed
    static __inline uint64_t
    
    rdtsc(void)
    {
    	return 0;
    }
    #endif
    
    int64_t ast_mark(int i, int startstop)
    {
    	if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
    		return 0;
    	if (startstop == 1)
    		prof_data->e[i].mark = rdtsc();
    	else {
    		prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
    		if (prof_data->e[i].scale > 1)
    			prof_data->e[i].mark /= prof_data->e[i].scale;
    		prof_data->e[i].value += prof_data->e[i].mark;
    		prof_data->e[i].events++;
    	}
    	return prof_data->e[i].mark;
    }
    
    
    #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
    	max = prof_data->entries;\
    	if  (a->argc > 3) { /* specific entries */ \
    		if (isdigit(a->argv[3][0])) { \