1999-11-15 04:57:28 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk -- An open source telephony toolkit.
1999-11-15 04:57:28 +00:00
*
2012-01-09 17:06:30 +00:00
* Copyright (C) 1999 - 2012, Digium, Inc.
1999-11-15 04:57:28 +00:00
*
2004-08-27 03:28:32 +00:00
* Mark Spencer <markster@digium.com>
1999-11-15 04:57:28 +00:00
*
2005-09-14 20:46:50 +00:00
* 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.
*
1999-11-15 04:57:28 +00:00
* This program is free software, distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
2005-10-24 20:12:06 +00:00
/* Doxygenified Copyright Header */
/*!
2009-10-30 04:08:39 +00:00
* \mainpage Asterisk -- The Open Source Telephony Project
2005-10-24 20:12:06 +00:00
*
2012-09-21 17:14:59 +00:00
* \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.
*
2012-10-01 23:39:45 +00:00
* \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
*
2005-11-14 19:00:38 +00:00
* \par Developer Documentation for Asterisk
2008-12-09 22:38:41 +00:00
*
2012-03-22 19:51:16 +00:00
* This is the main developer documentation for Asterisk. It is
* generated by running "make progdocs" from the Asterisk source tree.
2008-12-09 22:38:41 +00:00
*
2012-03-22 19:51:16 +00:00
* In addition to the information available on the Asterisk source code,
* please see the appendices for information on coding guidelines,
2008-12-09 22:38:41 +00:00
* release management, commit policies, and more.
*
2009-10-30 04:08:39 +00:00
* \arg \ref AsteriskArchitecture
*
2005-11-14 19:00:38 +00:00
* \par Additional documentation
2008-07-25 14:57:11 +00:00
* \arg \ref Licensing
2012-03-22 19:51:16 +00:00
* \arg \ref DevDoc
2012-10-01 23:39:45 +00:00
* \arg \ref configuration_file
2012-10-18 14:17:40 +00:00
* \arg \ref channel_drivers
* \arg \ref applications
2005-10-24 20:12:06 +00:00
*
2008-12-09 22:38:41 +00:00
* \section copyright Copyright and Author
2005-10-24 20:12:06 +00:00
*
2012-01-09 17:06:30 +00:00
* Copyright (C) 1999 - 2012, Digium, Inc.
2008-12-09 22:38:41 +00:00
* Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
* of <a href="http://www.digium.com">Digium, Inc</a>.
2005-10-24 20:12:06 +00:00
*
* \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;
2008-12-09 22:38:41 +00:00
* the project provides a web site, mailing lists, and IRC
2005-10-24 20:12:06 +00:00
* channels for your use.
2012-09-21 17:14:59 +00:00
*
2012-10-01 23:39:45 +00:00
*/
/*!
* \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.
*
* \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.
2005-10-24 20:12:06 +00:00
*/
/*! \file
2012-09-21 17:14:59 +00:00
* \brief Top level source file for Asterisk - the Open Source PBX.
* Implementation of PBX core functions and CLI interface.
1999-11-15 04:57:28 +00:00
*/
2012-10-18 14:17:40 +00:00
/*! \li \ref asterisk.c uses the configuration file \ref asterisk.conf
2012-10-01 23:39:45 +00:00
* \addtogroup configuration_file
*/
/*! \page asterisk.conf asterisk.conf
* \verbinclude asterisk.conf.sample
*/
2012-06-15 16:20:16 +00:00
/*** MODULEINFO
<support_level>core</support_level>
***/
2006-06-07 18:54:56 +00:00
#include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , "$Revision$" )
2007-11-20 22:18:21 +00:00
#include "asterisk/_private.h"
2007-04-09 03:04:07 +00:00
#undef sched_setscheduler
#undef setpriority
2005-04-29 17:24:58 +00:00
#include <sys/time.h>
2005-04-22 13:11:34 +00:00
#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>
2007-08-01 19:37:59 +00:00
#if defined(HAVE_SYSINFO)
2007-04-11 19:11:32 +00:00
#include <sys/sysinfo.h>
2008-12-16 20:08:34 +00:00
#elif defined(HAVE_SYSCTL)
#include <sys/param.h>
#include <sys/sysctl.h>
2009-01-14 19:36:57 +00:00
#if !defined(__OpenBSD__)
#include <sys/vmmeter.h>
#if defined(__FreeBSD__)
#include <vm/vm_param.h>
#endif
#endif
2009-01-12 14:35:09 +00:00
#if defined(HAVE_SWAPCTL)
2008-12-16 20:08:34 +00:00
#include <sys/swap.h>
2007-04-11 20:59:08 +00:00
#endif
2009-01-12 14:35:09 +00:00
#endif
2005-06-06 20:27:51 +00:00
#include <regex.h>
2012-07-25 12:21:54 +00:00
#include <histedit.h>
2005-04-22 13:11:34 +00:00
2006-03-02 22:27:50 +00:00
#if defined(SOLARIS)
2006-06-07 18:54:56 +00:00
int daemon ( int , int ); /* defined in libresolv of all places */
2007-09-12 16:24:45 +00:00
#include <sys/loadavg.h>
2006-03-02 22:27:50 +00:00
#endif
2005-04-22 13:11:34 +00:00
2008-04-08 17:00:55 +00:00
#ifdef linux
#include <sys/prctl.h>
#ifdef HAVE_CAP
#include <sys/capability.h>
#endif /* HAVE_CAP */
#endif /* linux */
2012-09-22 20:43:30 +00:00
/* we define here the variables so to better agree on the prototype */
#include "asterisk/paths.h"
2007-11-17 14:11:53 +00:00
#include "asterisk/network.h"
2005-04-21 06:02:45 +00:00
#include "asterisk/cli.h"
#include "asterisk/channel.h"
2011-02-03 16:22:10 +00:00
#include "asterisk/translate.h"
2008-01-23 23:09:11 +00:00
#include "asterisk/features.h"
2012-07-11 18:33:36 +00:00
#include "asterisk/acl.h"
2005-04-21 06:02:45 +00:00
#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"
2005-06-03 01:42:31 +00:00
#include "asterisk/cdr.h"
2009-06-26 15:28:53 +00:00
#include "asterisk/cel.h"
2005-04-21 06:02:45 +00:00
#include "asterisk/pbx.h"
#include "asterisk/enum.h"
2006-03-25 23:50:09 +00:00
#include "asterisk/http.h"
2006-01-12 17:14:58 +00:00
#include "asterisk/udptl.h"
2005-04-21 06:02:45 +00:00
#include "asterisk/app.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/io.h"
2003-02-06 06:15:25 +00:00
#include "editline/histedit.h"
2005-04-21 06:02:45 +00:00
#include "asterisk/config.h"
2008-02-26 20:33:08 +00:00
#include "asterisk/ast_version.h"
2005-06-06 20:27:51 +00:00
#include "asterisk/linkedlists.h"
2005-07-08 21:14:34 +00:00
#include "asterisk/devicestate.h"
2012-06-04 20:26:12 +00:00
#include "asterisk/presencestate.h"
2007-06-05 15:54:36 +00:00
#include "asterisk/module.h"
2008-03-05 16:23:44 +00:00
#include "asterisk/dsp.h"
2008-10-30 16:49:02 +00:00
#include "asterisk/buildinfo.h"
2008-11-10 13:53:23 +00:00
#include "asterisk/xmldoc.h"
2009-03-18 02:28:55 +00:00
#include "asterisk/poll-compat.h"
2010-04-09 15:31:32 +00:00
#include "asterisk/ccss.h"
2009-12-22 16:09:11 +00:00
#include "asterisk/test.h"
2011-02-22 23:04:49 +00:00
#include "asterisk/rtp_engine.h"
2011-02-03 16:22:10 +00:00
#include "asterisk/format.h"
2010-06-02 18:10:15 +00:00
#include "asterisk/aoc.h"
2012-12-11 21:04:45 +00:00
#include "asterisk/uuid.h"
2013-01-25 14:01:04 +00:00
#include "asterisk/sorcery.h"
2013-03-08 15:15:13 +00:00
#include "asterisk/stasis.h"
2013-03-22 19:26:37 +00:00
#include "asterisk/json.h"
2005-06-06 03:04:58 +00:00
2006-08-21 02:11:39 +00:00
#include "../defaults.h"
2004-04-28 13:53:01 +00:00
2012-07-11 02:06:05 +00:00
/*** DOCUMENTATION
***/
2004-12-14 23:36:30 +00:00
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#define PF_LOCAL PF_UNIX
#endif
2001-05-09 03:11:22 +00:00
#define AST_MAX_CONNECTS 128
#define NUM_MSGS 64
2012-04-25 09:32:21 +00:00
/*! Default minimum DTMF digit length - 80ms */
#define AST_MIN_DTMF_DURATION 80
2005-11-14 19:00:38 +00:00
/*! \brief Welcome message when starting a CLI interface */
2005-12-23 03:04:38 +00:00
#define WELCOME_MESSAGE \
2012-01-09 17:06:30 +00:00
ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
2007-02-13 06:02:57 +00:00
"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" \
2008-02-12 15:39:44 +00:00
"=========================================================================\n", ast_get_version()) \
2004-06-25 21:14:03 +00:00
2006-10-30 16:33:02 +00:00
/*! \defgroup main_options Main Configuration Options
2007-07-23 14:32:04 +00:00
* \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
* \arg \ref Config_ast "asterisk.conf"
2012-03-22 19:51:16 +00:00
* \note Some of them can be changed in the CLI
2005-11-14 19:00:38 +00:00
*/
/*! @{ */
2005-12-04 20:40:46 +00:00
2006-03-14 16:57:35 +00:00
struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
2010-01-15 23:50:47 +00:00
struct ast_flags ast_compat = { 0 };
2005-12-04 20:40:46 +00:00
2006-12-27 22:14:33 +00:00
int option_verbose ; /*!< Verbosity level */
int option_debug ; /*!< Debug level */
double option_maxload ; /*!< Max load avg on system */
int option_maxcalls ; /*!< Max number of active calls */
2007-02-14 20:22:20 +00:00
int option_maxfiles ; /*!< Max number of open file handles (files, sockets) */
2012-04-25 09:32:21 +00:00
unsigned int option_dtmfminduration ; /*!< Minimum duration of DTMF. */
2007-08-01 19:37:59 +00:00
#if defined(HAVE_SYSINFO)
2007-04-11 19:11:32 +00:00
long option_minmemfree ; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
2007-04-11 20:59:08 +00:00
#endif
2005-11-14 19:00:38 +00:00
/*! @} */
2009-03-27 14:00:18 +00:00
struct ast_eid ast_eid_default ;
2008-06-10 12:48:50 +00:00
2007-12-18 09:26:03 +00:00
/* 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 ;
1999-12-19 22:38:55 +00:00
2005-10-24 20:12:06 +00:00
static int ast_socket = - 1 ; /*!< UNIX Socket for allowing remote control */
static int ast_consock = - 1 ; /*!< UNIX Socket for controlling another asterisk */
2006-05-08 12:32:44 +00:00
pid_t ast_mainpid ;
2001-05-09 03:11:22 +00:00
struct console {
2005-10-24 20:12:06 +00:00
int fd ; /*!< File descriptor */
int p [ 2 ]; /*!< Pipe */
pthread_t t ; /*!< Thread of handler */
2006-05-26 19:48:17 +00:00
int mute ; /*!< Is the console muted for logs */
2008-12-01 18:52:14 +00:00
int uid ; /*!< Remote user ID. */
int gid ; /*!< Remote group ID. */
2008-05-29 21:30:37 +00:00
int levels [ NUMLOGLEVELS ]; /*!< Which log levels are enabled for the console */
2001-05-09 03:11:22 +00:00
};
2006-01-24 20:27:09 +00:00
struct ast_atexit {
2003-08-07 03:48:00 +00:00
void ( * func )( void );
2012-12-03 23:00:08 +00:00
AST_LIST_ENTRY ( ast_atexit ) list ;
2006-01-24 20:27:09 +00:00
};
2005-10-24 20:12:06 +00:00
2012-12-03 23:00:08 +00:00
static AST_LIST_HEAD_STATIC ( atexits , ast_atexit );
2003-08-07 03:48:00 +00:00
2007-07-18 19:47:20 +00:00
struct timeval ast_startuptime ;
struct timeval ast_lastreloadtime ;
2003-05-02 15:37:34 +00:00
2006-12-27 22:14:33 +00:00
static History * el_hist ;
static EditLine * el ;
2003-02-06 06:15:25 +00:00
static char * remotehostname ;
2001-05-09 03:11:22 +00:00
struct console consoles [ AST_MAX_CONNECTS ];
2000-01-09 19:58:18 +00:00
char defaultlanguage [ MAX_LANGUAGE ] = DEFAULT_LANGUAGE ;
2003-02-06 06:15:25 +00:00
static int ast_el_add_history ( char * );
static int ast_el_read_history ( char * );
static int ast_el_write_history ( char * );
2007-12-20 09:55:05 +00:00
struct _cfg_paths {
char config_dir [ PATH_MAX ];
char module_dir [ PATH_MAX ];
char spool_dir [ PATH_MAX ];
char monitor_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 ];
2011-12-07 20:15:29 +00:00
char sbin_dir [ PATH_MAX ];
2007-12-20 09:55:05 +00:00
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_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 ;
2011-12-07 20:15:29 +00:00
const char * ast_config_AST_SBIN_DIR = cfg_paths . sbin_dir ;
2007-12-20 09:55:05 +00:00
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" ;
2003-02-06 06:15:25 +00:00
2010-09-02 05:02:54 +00:00
extern unsigned int ast_FD_SETSIZE ;
2004-02-23 03:43:21 +00:00
static char * _argv [ 256 ];
2012-01-15 20:16:08 +00:00
typedef enum {
NOT_SHUTTING_DOWN = - 2 ,
SHUTTING_DOWN = - 1 ,
/* Valid values for quit_handler niceness below: */
SHUTDOWN_FAST ,
SHUTDOWN_NORMAL ,
SHUTDOWN_NICE ,
SHUTDOWN_REALLY_NICE
} shutdown_nice_t ;
static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN ;
2006-12-27 22:14:33 +00:00
static int restartnow ;
2004-03-15 07:51:22 +00:00
static pthread_t consolethread = AST_PTHREADT_NULL ;
2010-10-08 03:00:40 +00:00
static pthread_t mon_sig_flags ;
2007-12-18 23:06:05 +00:00
static int canary_pid = 0 ;
static char canary_filename [ 128 ];
2012-11-18 20:27:45 +00:00
static int multi_thread_safe ;
2004-02-23 03:43:21 +00:00
2006-01-10 00:55:45 +00:00
static char randompool [ 256 ];
2007-02-23 23:25:22 +00:00
static int sig_alert_pipe [ 2 ] = { - 1 , - 1 };
static struct {
unsigned int need_reload : 1 ;
unsigned int need_quit : 1 ;
2011-07-18 12:54:29 +00:00
unsigned int need_quit_handler : 1 ;
2007-02-23 23:25:22 +00:00
} sig_flags ;
2007-01-30 17:23:56 +00:00
2005-06-07 16:07:06 +00:00
#if !defined(LOW_MEMORY)
2005-06-06 20:27:51 +00:00
struct file_version {
2007-06-18 16:37:14 +00:00
AST_RWLIST_ENTRY ( file_version ) list ;
2005-06-06 21:09:59 +00:00
const char * file ;
char * version ;
2005-06-06 20:27:51 +00:00
};
2007-06-18 16:37:14 +00:00
static AST_RWLIST_HEAD_STATIC ( file_versions , file_version );
2005-06-06 20:27:51 +00:00
void ast_register_file_version ( const char * file , const char * version )
{
struct file_version * new ;
2005-06-06 21:09:59 +00:00
char * work ;
size_t version_length ;
2005-06-06 20:27:51 +00:00
2005-06-06 21:09:59 +00:00
work = ast_strdupa ( version );
work = ast_strip ( ast_strip_quoted ( work , "$" , "$" ));
version_length = strlen ( work ) + 1 ;
2012-03-22 19:51:16 +00:00
2006-02-14 22:28:01 +00:00
if ( ! ( new = ast_calloc ( 1 , sizeof ( * new ) + version_length )))
2005-06-06 20:27:51 +00:00
return ;
new -> file = file ;
2005-06-06 21:09:59 +00:00
new -> version = ( char * ) new + sizeof ( * new );
memcpy ( new -> version , work , version_length );
2007-06-18 16:37:14 +00:00
AST_RWLIST_WRLOCK ( & file_versions );
AST_RWLIST_INSERT_HEAD ( & file_versions , new , list );
AST_RWLIST_UNLOCK ( & file_versions );
2005-06-06 20:27:51 +00:00
}
void ast_unregister_file_version ( const char * file )
{
struct file_version * find ;
2007-06-18 16:37:14 +00:00
AST_RWLIST_WRLOCK ( & file_versions );
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & file_versions , find , list ) {
2005-06-06 20:27:51 +00:00
if ( ! strcasecmp ( find -> file , file )) {
2007-11-08 05:28:47 +00:00
AST_RWLIST_REMOVE_CURRENT ( list );
2005-06-06 20:27:51 +00:00
break ;
}
}
2007-06-18 16:37:14 +00:00
AST_RWLIST_TRAVERSE_SAFE_END ;
AST_RWLIST_UNLOCK ( & file_versions );
2007-06-08 15:32:46 +00:00
2005-06-06 21:09:59 +00:00
if ( find )
2007-06-06 21:20:11 +00:00
ast_free ( find );
2005-06-06 20:27:51 +00:00
}
2008-12-10 17:09:15 +00:00
char * ast_complete_source_filename ( const char * partial , int n )
{
struct file_version * find ;
size_t len = strlen ( partial );
int count = 0 ;
char * res = NULL ;
AST_RWLIST_RDLOCK ( & file_versions );
AST_RWLIST_TRAVERSE ( & file_versions , find , list ) {
if ( ! strncasecmp ( find -> file , partial , len ) && ++ count > n ) {
res = ast_strdup ( find -> file );
break ;
}
}
AST_RWLIST_UNLOCK ( & file_versions );
return res ;
}
2007-11-27 21:04:29 +00:00
/*! \brief Find version for given module name */
const char * ast_file_version_find ( const char * file )
{
struct file_version * iterator ;
AST_RWLIST_WRLOCK ( & file_versions );
2011-05-03 20:45:32 +00:00
AST_RWLIST_TRAVERSE ( & file_versions , iterator , list ) {
2007-11-27 21:04:29 +00:00
if ( ! strcasecmp ( iterator -> file , file ))
break ;
2011-05-03 20:45:32 +00:00
}
2007-11-27 21:04:29 +00:00
AST_RWLIST_UNLOCK ( & file_versions );
if ( iterator )
return iterator -> version ;
return NULL ;
2012-03-22 19:51:16 +00:00
}
2006-04-12 20:40:46 +00:00
struct thread_list_t {
2007-06-18 16:37:14 +00:00
AST_RWLIST_ENTRY ( thread_list_t ) list ;
2006-04-12 20:40:46 +00:00
char * name ;
pthread_t id ;
2010-12-12 03:58:33 +00:00
int lwp ;
2006-04-12 20:40:46 +00:00
};
2007-06-18 16:37:14 +00:00
static AST_RWLIST_HEAD_STATIC ( thread_list , thread_list_t );
2006-04-12 20:40:46 +00:00
void ast_register_thread ( char * name )
2012-03-22 19:51:16 +00:00
{
2006-04-12 20:40:46 +00:00
struct thread_list_t * new = ast_calloc ( 1 , sizeof ( * new ));
if ( ! new )
return ;
2012-11-18 20:27:45 +00:00
ast_assert ( multi_thread_safe );
2006-04-12 20:40:46 +00:00
new -> id = pthread_self ();
2010-12-12 03:58:33 +00:00
new -> lwp = ast_get_tid ();
2006-10-04 19:51:38 +00:00
new -> name = name ; /* steal the allocated memory for the thread name */
2007-06-18 16:37:14 +00:00
AST_RWLIST_WRLOCK ( & thread_list );
AST_RWLIST_INSERT_HEAD ( & thread_list , new , list );
AST_RWLIST_UNLOCK ( & thread_list );
2006-04-12 20:40:46 +00:00
}
void ast_unregister_thread ( void * id )
{
struct thread_list_t * x ;
2007-06-18 16:37:14 +00:00
AST_RWLIST_WRLOCK ( & thread_list );
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & thread_list , x , list ) {
2006-10-04 19:51:38 +00:00
if (( void * ) x -> id == id ) {
2007-11-08 05:28:47 +00:00
AST_RWLIST_REMOVE_CURRENT ( list );
2006-04-12 20:40:46 +00:00
break ;
}
}
2007-06-18 16:37:14 +00:00
AST_RWLIST_TRAVERSE_SAFE_END ;
AST_RWLIST_UNLOCK ( & thread_list );
2006-04-12 20:40:46 +00:00
if ( x ) {
2007-06-06 21:20:11 +00:00
ast_free ( x -> name );
ast_free ( x );
2006-04-12 20:40:46 +00:00
}
}
2007-02-14 20:22:20 +00:00
/*! \brief Give an overview of core settings */
2007-10-11 19:03:06 +00:00
static char * handle_show_settings ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2007-02-14 20:22:20 +00:00
{
char buf [ BUFSIZ ];
2007-07-18 19:47:20 +00:00
struct ast_tm tm ;
2008-06-10 12:48:50 +00:00
char eid_str [ 128 ];
2007-02-14 20:22:20 +00:00
2007-10-11 19:03:06 +00:00
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 ;
}
2009-03-27 14:00:18 +00:00
ast_eid_to_str ( eid_str , sizeof ( eid_str ), & ast_eid_default );
2008-06-10 12:48:50 +00:00
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " \n PBX Core settings \n " );
ast_cli ( a -> fd , "----------------- \n " );
2008-01-05 22:09:06 +00:00
ast_cli ( a -> fd , " Version: %s \n " , ast_get_version ());
2008-05-22 13:40:52 +00:00
ast_cli ( a -> fd , " Build Options: %s \n " , S_OR ( AST_BUILDOPTS , "(none)" ));
2007-02-14 20:22:20 +00:00
if ( option_maxcalls )
2008-02-18 19:47:40 +00:00
ast_cli ( a -> fd , " Maximum calls: %d (Current %d) \n " , option_maxcalls , ast_active_channels ());
2007-02-14 20:22:20 +00:00
else
2008-02-18 19:47:40 +00:00
ast_cli ( a -> fd , " Maximum calls: Not set \n " );
2007-02-14 20:22:20 +00:00
if ( option_maxfiles )
2012-03-22 19:51:16 +00:00
ast_cli ( a -> fd , " Maximum open file handles: %d \n " , option_maxfiles );
2007-02-14 20:22:20 +00:00
else
2008-02-18 19:47:40 +00:00
ast_cli ( a -> fd , " Maximum open file handles: Not set \n " );
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " Verbosity: %d \n " , option_verbose );
ast_cli ( a -> fd , " Debug level: %d \n " , option_debug );
2008-02-18 19:47:40 +00:00
ast_cli ( a -> fd , " Maximum load average: %lf \n " , option_maxload );
2007-08-01 19:37:59 +00:00
#if defined(HAVE_SYSINFO)
2008-02-18 19:47:40 +00:00
ast_cli ( a -> fd , " Minimum free memory: %ld MB \n " , option_minmemfree );
2007-04-11 20:59:08 +00:00
#endif
2007-06-14 22:09:20 +00:00
if ( ast_localtime ( & ast_startuptime , & tm , NULL )) {
2007-07-18 19:47:20 +00:00
ast_strftime ( buf , sizeof ( buf ), "%H:%M:%S" , & tm );
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " Startup time: %s \n " , buf );
2007-02-14 20:22:20 +00:00
}
2007-06-14 22:09:20 +00:00
if ( ast_localtime ( & ast_lastreloadtime , & tm , NULL )) {
2007-07-18 19:47:20 +00:00
ast_strftime ( buf , sizeof ( buf ), "%H:%M:%S" , & tm );
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " Last reload time: %s \n " , buf );
2007-02-14 20:22:20 +00:00
}
2007-10-11 19:03:06 +00:00
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 );
2008-06-10 12:48:50 +00:00
ast_cli ( a -> fd , " Entity ID: %s \n " , eid_str );
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " Default language: %s \n " , 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 , " Internal timing: %s \n " , ast_test_flag ( & ast_options , AST_OPT_FLAG_INTERNAL_TIMING ) ? "Enabled" : "Disabled" );
2009-04-17 19:36:38 +00:00
ast_cli ( a -> fd , " Transmit silence during rec: %s \n " , ast_test_flag ( & ast_options , AST_OPT_FLAG_TRANSMIT_SILENCE ) ? "Enabled" : "Disabled" );
2010-05-19 21:29:08 +00:00
ast_cli ( a -> fd , " Generic PLC: %s \n " , ast_test_flag ( & ast_options , AST_OPT_FLAG_GENERIC_PLC ) ? "Enabled" : "Disabled" );
2012-04-25 09:32:21 +00:00
ast_cli ( a -> fd , " Min DTMF duration:: %u \n " , option_dtmfminduration );
2007-10-11 19:03:06 +00:00
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 " , check_cdr_enabled () ? "Enabled" : "Disabled" );
ast_cli ( a -> fd , " Realtime Architecture (ARA): %s \n " , ast_realtime_enabled () ? "Enabled" : "Disabled" );
2007-02-14 20:22:20 +00:00
/*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
2007-10-11 19:03:06 +00:00
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 );
2010-03-23 22:48:03 +00:00
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 );
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " \n\n " );
return CLI_SUCCESS ;
2007-02-14 20:22:20 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_show_threads ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-04-12 20:40:46 +00:00
{
int count = 0 ;
struct thread_list_t * cur ;
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "core show threads" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2007-10-11 19:03:06 +00:00
"Usage: core show threads \n "
" List threads currently active in the system. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2006-04-12 20:40:46 +00:00
2007-06-18 16:37:14 +00:00
AST_RWLIST_RDLOCK ( & thread_list );
AST_RWLIST_TRAVERSE ( & thread_list , cur , list ) {
2010-12-12 03:58:33 +00:00
ast_cli ( a -> fd , "%p %d %s \n " , ( void * ) cur -> id , cur -> lwp , cur -> name );
2006-04-12 20:40:46 +00:00
count ++ ;
}
2012-03-22 19:51:16 +00:00
AST_RWLIST_UNLOCK ( & thread_list );
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , "%d threads listed. \n " , count );
return CLI_SUCCESS ;
2006-04-12 20:40:46 +00:00
}
2008-12-16 20:08:34 +00:00
#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 ;
}
2008-12-16 20:49:25 +00:00
#elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
2008-12-16 20:08:34 +00:00
static int swapmode ( int * used , int * total )
{
2009-01-19 20:14:27 +00:00
* used = * total = 0 ;
2008-12-16 20:08:34 +00:00
return 1 ;
}
#endif
2009-02-21 14:37:04 +00:00
#if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2007-04-11 19:11:32 +00:00
/*! \brief Give an overview of system statistics */
2007-10-11 19:03:06 +00:00
static char * handle_show_sysinfo ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2007-04-11 19:11:32 +00:00
{
2010-05-24 18:19:08 +00:00
uint64_t physmem , freeram ;
2010-05-28 20:53:04 +00:00
uint64_t freeswap = 0 ;
2010-05-24 18:19:08 +00:00
int nprocs = 0 ;
2008-12-16 20:08:34 +00:00
long uptime = 0 ;
2011-05-03 20:45:32 +00:00
int totalswap = 0 ;
2008-12-16 20:08:34 +00:00
#if defined(HAVE_SYSINFO)
2007-04-11 19:11:32 +00:00
struct sysinfo sys_info ;
2008-12-16 20:49:25 +00:00
sysinfo ( & sys_info );
2010-05-24 18:19:08 +00:00
uptime = sys_info . uptime / 3600 ;
2008-12-16 20:08:34 +00:00
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 ;
2008-12-16 20:49:25 +00:00
nprocs = sys_info . procs ;
2008-12-16 20:08:34 +00:00
#elif defined(HAVE_SYSCTL)
static int pageshift ;
struct vmtotal vmtotal ;
struct timeval boottime ;
time_t now ;
2009-01-14 19:36:57 +00:00
int mib [ 2 ], pagesize , usedswap = 0 ;
2008-12-16 20:08:34 +00:00
size_t len ;
/* 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 ;
2009-01-19 18:36:24 +00:00
#if defined(HW_PHYSMEM64)
2008-12-16 20:08:34 +00:00
mib [ 1 ] = HW_PHYSMEM64 ;
2009-01-14 19:36:57 +00:00
#else
mib [ 1 ] = HW_PHYSMEM ;
#endif
2008-12-16 20:08:34 +00:00
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 */
2010-05-24 18:19:08 +00:00
swapmode ( & usedswap , & totalswap );
2008-12-16 20:08:34 +00:00
freeswap = ( totalswap - usedswap );
/* grab number of processes */
2009-01-14 19:36:57 +00:00
#if defined(__OpenBSD__)
2008-12-16 20:08:34 +00:00
mib [ 0 ] = CTL_KERN ;
mib [ 1 ] = KERN_NPROCS ;
len = sizeof ( nprocs );
sysctl ( mib , 2 , & nprocs , & len , NULL , 0 );
2009-01-14 19:36:57 +00:00
#endif
2008-12-16 20:08:34 +00:00
#endif
2007-10-11 19:03:06 +00:00
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 ;
}
2008-12-16 20:08:34 +00:00
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " \n System Statistics \n " );
ast_cli ( a -> fd , "----------------- \n " );
2010-05-24 18:19:08 +00:00
ast_cli ( a -> fd , " System Uptime: %lu hours \n " , uptime );
ast_cli ( a -> fd , " Total RAM: %" PRIu64 " KiB \n " , physmem / 1024 );
ast_cli ( a -> fd , " Free RAM: %" PRIu64 " KiB \n " , freeram );
2008-12-16 20:08:34 +00:00
#if defined(HAVE_SYSINFO)
2010-05-24 18:19:08 +00:00
ast_cli ( a -> fd , " Buffer RAM: %" PRIu64 " KiB \n " , (( uint64_t ) sys_info . bufferram * sys_info . mem_unit ) / 1024 );
2008-12-16 20:08:34 +00:00
#endif
2011-05-03 20:45:32 +00:00
#if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
2010-05-28 20:53:04 +00:00
ast_cli ( a -> fd , " Total Swap Space: %u KiB \n " , totalswap );
2010-05-24 18:19:08 +00:00
ast_cli ( a -> fd , " Free Swap Space: %" PRIu64 " KiB \n\n " , freeswap );
2010-05-28 20:53:04 +00:00
#endif
2008-12-16 20:08:34 +00:00
ast_cli ( a -> fd , " Number of Processes: %d \n\n " , nprocs );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2007-04-11 19:11:32 +00:00
}
2009-02-21 14:37:04 +00:00
#endif
2007-04-11 19:11:32 +00:00
2006-04-12 20:40:46 +00:00
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 ;
2006-06-08 18:03:08 +00:00
/*! \brief allocates a counter with a given name and scale.
* \return Returns the identifier of the counter.
2006-04-12 20:40:46 +00:00
*/
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 ;
}
2008-06-19 16:08:29 +00:00
/* 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))
2006-04-12 20:40:46 +00:00
#if defined(__FreeBSD__)
#include <machine/cpufunc.h>
#elif defined(linux)
2006-08-22 05:34:44 +00:00
static __inline uint64_t
2006-04-12 20:40:46 +00:00
rdtsc ( void )
2012-03-22 19:51:16 +00:00
{
2006-04-12 20:40:46 +00:00
uint64_t rv ;
__asm __volatile ( ".byte 0x0f, 0x31" : "=A" ( rv ));
return ( rv );
}
#endif
#else /* supply a dummy function on other platforms */
2006-08-22 05:34:44 +00:00
static __inline uint64_t
2006-04-12 20:40:46 +00:00
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 ;
}
2007-10-11 19:03:06 +00:00
#define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
max = prof_data->entries;\
if (a->argc > 3) { /* specific entries */ \
if (isdigit(a->argv[3][0])) { \
min = atoi(a->argv[3]); \
if (a->argc == 5 && strcmp(a->argv[4], "-")) \
max = atoi(a->argv[4]); \
} else \
search = a->argv[3]; \
} \
if (max > prof_data->entries) \
max = prof_data->entries;
static char * handle_show_profile ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-09-18 19:54:18 +00:00
{
int i , min , max ;
2009-05-21 21:13:09 +00:00
const char * search = NULL ;
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "core show profile" ;
e -> usage = "Usage: core show profile \n "
" show profile information" ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2006-09-18 19:54:18 +00:00
if ( prof_data == NULL )
return 0 ;
2007-10-11 19:03:06 +00:00
DEFINE_PROFILE_MIN_MAX_VALUES ;
ast_cli ( a -> fd , "profile values (%d, allocated %d) \n ------------------- \n " ,
2006-09-18 19:54:18 +00:00
prof_data -> entries , prof_data -> max_size );
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , "%6s %8s %10s %12s %12s %s \n " , "ID" , "Scale" , "Events" ,
2006-09-18 19:54:18 +00:00
"Value" , "Average" , "Name" );
for ( i = min ; i < max ; i ++ ) {
2008-08-10 19:35:50 +00:00
struct profile_entry * entry = & prof_data -> e [ i ];
2008-08-10 20:23:50 +00:00
if ( ! search || strstr ( entry -> name , search ))
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , "%6d: [%8ld] %10ld %12lld %12lld %s \n " ,
2006-09-18 19:54:18 +00:00
i ,
2008-08-10 19:35:50 +00:00
( long ) entry -> scale ,
( long ) entry -> events , ( long long ) entry -> value ,
( long long )( entry -> events ? entry -> value / entry -> events : entry -> value ),
entry -> name );
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_clear_profile ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
{
int i , min , max ;
2009-05-21 21:13:09 +00:00
const char * search = NULL ;
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "core clear profile" ;
e -> usage = "Usage: core clear profile \n "
" clear profile information" ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( prof_data == NULL )
return 0 ;
DEFINE_PROFILE_MIN_MAX_VALUES ;
for ( i = min ; i < max ; i ++ ) {
if ( ! search || strstr ( prof_data -> e [ i ]. name , search )) {
prof_data -> e [ i ]. value = 0 ;
prof_data -> e [ i ]. events = 0 ;
}
}
return CLI_SUCCESS ;
}
#undef DEFINE_PROFILE_MIN_MAX_VALUES
2005-06-06 20:27:51 +00:00
2006-06-08 18:03:08 +00:00
/*! \brief CLI command to list module versions */
2007-10-11 19:03:06 +00:00
static char * handle_show_version_files ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2005-06-06 20:27:51 +00:00
{
2005-07-25 22:19:13 +00:00
#define FORMAT "%-25.25s %-40.40s\n"
2005-06-06 20:27:51 +00:00
struct file_version * iterator ;
2005-06-06 21:09:59 +00:00
regex_t regexbuf ;
int havepattern = 0 ;
2005-06-06 22:39:32 +00:00
int havename = 0 ;
2005-08-22 18:45:41 +00:00
int count_files = 0 ;
2007-10-11 19:03:06 +00:00
char * ret = NULL ;
int matchlen , which = 0 ;
struct file_version * find ;
switch ( cmd ) {
case CLI_INIT :
e -> command = "core show file version [like]" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2007-10-11 19:03:06 +00:00
"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 " ;
return NULL ;
case CLI_GENERATE :
matchlen = strlen ( a -> word );
if ( a -> pos != 3 )
return NULL ;
AST_RWLIST_RDLOCK ( & file_versions );
AST_RWLIST_TRAVERSE ( & file_versions , find , list ) {
if ( ! strncasecmp ( a -> word , find -> file , matchlen ) && ++ which > a -> n ) {
ret = ast_strdup ( find -> file );
break ;
}
}
AST_RWLIST_UNLOCK ( & file_versions );
return ret ;
}
2005-06-06 21:09:59 +00:00
2007-10-11 19:03:06 +00:00
switch ( a -> argc ) {
2007-02-26 16:38:10 +00:00
case 6 :
2007-10-11 19:03:06 +00:00
if ( ! strcasecmp ( a -> argv [ 4 ], "like" )) {
if ( regcomp ( & regexbuf , a -> argv [ 5 ], REG_EXTENDED | REG_NOSUB ))
return CLI_SHOWUSAGE ;
2005-06-06 21:09:59 +00:00
havepattern = 1 ;
} else
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2005-06-06 21:09:59 +00:00
break ;
2007-02-26 16:38:10 +00:00
case 5 :
2005-06-06 22:39:32 +00:00
havename = 1 ;
break ;
2007-02-26 16:38:10 +00:00
case 4 :
2005-06-06 21:09:59 +00:00
break ;
default :
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2005-06-06 21:09:59 +00:00
}
2005-06-06 20:27:51 +00:00
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , FORMAT , "File" , "Revision" );
ast_cli ( a -> fd , FORMAT , "----" , "--------" );
2007-06-18 16:37:14 +00:00
AST_RWLIST_RDLOCK ( & file_versions );
AST_RWLIST_TRAVERSE ( & file_versions , iterator , list ) {
2007-10-11 19:03:06 +00:00
if ( havename && strcasecmp ( iterator -> file , a -> argv [ 4 ]))
2005-06-06 22:39:32 +00:00
continue ;
2005-06-06 21:09:59 +00:00
if ( havepattern && regexec ( & regexbuf , iterator -> file , 0 , NULL , 0 ))
continue ;
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , FORMAT , iterator -> file , iterator -> version );
2005-08-22 18:45:41 +00:00
count_files ++ ;
2005-06-06 22:39:32 +00:00
if ( havename )
break ;
2005-06-06 20:27:51 +00:00
}
2007-06-18 16:37:14 +00:00
AST_RWLIST_UNLOCK ( & file_versions );
2005-08-22 18:45:41 +00:00
if ( ! havename ) {
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , "%d files listed. \n " , count_files );
2005-08-22 18:45:41 +00:00
}
2005-06-06 21:09:59 +00:00
if ( havepattern )
regfree ( & regexbuf );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2005-06-06 21:09:59 +00:00
#undef FORMAT
2005-06-06 20:27:51 +00:00
}
2005-06-07 16:07:06 +00:00
#endif /* ! LOW_MEMORY */
2005-06-06 20:27:51 +00:00
2012-12-03 23:00:08 +00:00
static void ast_run_atexits ( void )
{
struct ast_atexit * ae ;
AST_LIST_LOCK ( & atexits );
while (( ae = AST_LIST_REMOVE_HEAD ( & atexits , list ))) {
if ( ae -> func ) {
ae -> func ();
}
ast_free ( ae );
}
AST_LIST_UNLOCK ( & atexits );
}
static void __ast_unregister_atexit ( void ( * func )( void ))
{
struct ast_atexit * ae ;
AST_LIST_TRAVERSE_SAFE_BEGIN ( & atexits , ae , list ) {
if ( ae -> func == func ) {
AST_LIST_REMOVE_CURRENT ( list );
ast_free ( ae );
break ;
}
}
AST_LIST_TRAVERSE_SAFE_END ;
}
2003-08-07 03:48:00 +00:00
int ast_register_atexit ( void ( * func )( void ))
{
struct ast_atexit * ae ;
2007-09-08 18:45:51 +00:00
2012-12-03 23:00:08 +00:00
ae = ast_calloc ( 1 , sizeof ( * ae ));
if ( ! ae ) {
2007-09-08 18:45:51 +00:00
return - 1 ;
2012-12-03 23:00:08 +00:00
}
2007-09-08 18:45:51 +00:00
ae -> func = func ;
2012-12-03 23:00:08 +00:00
AST_LIST_LOCK ( & atexits );
__ast_unregister_atexit ( func );
AST_LIST_INSERT_HEAD ( & atexits , ae , list );
AST_LIST_UNLOCK ( & atexits );
2007-09-08 18:45:51 +00:00
return 0 ;
2003-08-07 03:48:00 +00:00
}
void ast_unregister_atexit ( void ( * func )( void ))
{
2012-12-03 23:00:08 +00:00
AST_LIST_LOCK ( & atexits );
__ast_unregister_atexit ( func );
AST_LIST_UNLOCK ( & atexits );
2003-08-07 03:48:00 +00:00
}
2008-05-27 18:59:06 +00:00
/* Sending commands from consoles back to the daemon requires a terminating NULL */
static int fdsend ( int fd , const char * s )
2001-05-09 03:11:22 +00:00
{
return write ( fd , s , strlen ( s ) + 1 );
}
2008-05-27 18:59:06 +00:00
/* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
static int fdprint ( int fd , const char * s )
{
return write ( fd , s , strlen ( s ));
}
2006-06-08 18:03:08 +00:00
/*! \brief NULL handler so we can collect the child exit status */
2010-05-26 21:17:46 +00:00
static void _null_sig_handler ( int sig )
2004-08-22 18:33:19 +00:00
{
}
2010-05-26 21:17:46 +00:00
static struct sigaction null_sig_handler = {
. sa_handler = _null_sig_handler ,
2010-06-10 08:15:45 +00:00
. sa_flags = SA_RESTART ,
2010-05-26 21:17:46 +00:00
};
static struct sigaction ignore_sig_handler = {
. sa_handler = SIG_IGN ,
};
2005-09-14 22:40:54 +00:00
AST_MUTEX_DEFINE_STATIC ( safe_system_lock );
2006-06-08 18:03:08 +00:00
/*! \brief Keep track of how many threads are currently trying to wait*() on
2012-09-21 17:14:59 +00:00
* a child process
*/
2005-09-14 22:40:54 +00:00
static unsigned int safe_system_level = 0 ;
2010-05-26 21:17:46 +00:00
static struct sigaction safe_system_prev_handler ;
2005-09-14 22:40:54 +00:00
2006-05-25 18:31:19 +00:00
void ast_replace_sigchld ( void )
2004-03-21 18:15:37 +00:00
{
2005-09-14 22:40:54 +00:00
unsigned int level ;
ast_mutex_lock ( & safe_system_lock );
level = safe_system_level ++ ;
/* only replace the handler if it has not already been done */
2010-05-26 21:17:46 +00:00
if ( level == 0 ) {
sigaction ( SIGCHLD , & null_sig_handler , & safe_system_prev_handler );
}
2005-09-14 22:40:54 +00:00
ast_mutex_unlock ( & safe_system_lock );
2006-05-25 18:31:19 +00:00
}
void ast_unreplace_sigchld ( void )
{
unsigned int level ;
ast_mutex_lock ( & safe_system_lock );
level = -- safe_system_level ;
/* only restore the handler if we are the last one */
2010-05-26 21:17:46 +00:00
if ( level == 0 ) {
sigaction ( SIGCHLD , & safe_system_prev_handler , NULL );
}
2006-05-25 18:31:19 +00:00
ast_mutex_unlock ( & safe_system_lock );
}
int ast_safe_system ( const char * s )
{
pid_t pid ;
int res ;
struct rusage rusage ;
int status ;
2006-09-16 23:53:58 +00:00
#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
ast_replace_sigchld ();
2005-09-14 22:40:54 +00:00
2006-09-18 19:58:27 +00:00
#ifdef HAVE_WORKING_FORK
2004-03-21 18:15:37 +00:00
pid = fork ();
2006-09-18 19:58:27 +00:00
#else
pid = vfork ();
2012-03-22 19:51:16 +00:00
#endif
2005-09-14 22:40:54 +00:00
2004-03-21 18:15:37 +00:00
if ( pid == 0 ) {
2009-01-29 23:15:40 +00:00
#ifdef HAVE_CAP
cap_t cap = cap_from_text ( "cap_net_admin-eip" );
if ( cap_set_proc ( cap )) {
/* Careful with order! Logging cannot happen after we close FDs */
ast_log ( LOG_WARNING , "Unable to remove capabilities. \n " );
}
cap_free ( cap );
#endif
2006-10-18 21:05:52 +00:00
#ifdef HAVE_WORKING_FORK
2006-05-01 21:48:30 +00:00
if ( ast_opt_high_priority )
ast_set_priority ( 0 );
2004-03-21 18:15:37 +00:00
/* Close file descriptors and launch system command */
2008-04-16 22:57:54 +00:00
ast_close_fds_above_n ( STDERR_FILENO );
2006-10-18 21:05:52 +00:00
#endif
2006-06-09 20:26:25 +00:00
execl ( "/bin/sh" , "/bin/sh" , "-c" , s , ( char * ) NULL );
2006-10-27 17:42:57 +00:00
_exit ( 1 );
2004-03-21 18:15:37 +00:00
} else if ( pid > 0 ) {
2007-01-23 00:11:32 +00:00
for (;;) {
2004-03-21 18:15:37 +00:00
res = wait4 ( pid , & status , 0 , & rusage );
if ( res > - 1 ) {
2005-09-14 22:40:54 +00:00
res = WIFEXITED ( status ) ? WEXITSTATUS ( status ) : - 1 ;
break ;
2012-03-22 19:51:16 +00:00
} else if ( errno != EINTR )
2004-06-21 19:12:20 +00:00
break ;
2004-03-21 18:15:37 +00:00
}
} else {
ast_log ( LOG_WARNING , "Fork failed: %s \n " , strerror ( errno ));
res = - 1 ;
}
2005-09-14 22:40:54 +00:00
2006-05-25 18:31:19 +00:00
ast_unreplace_sigchld ();
2009-01-29 23:15:40 +00:00
#else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
2006-08-21 20:12:18 +00:00
res = - 1 ;
#endif
2005-09-14 22:40:54 +00:00
2004-03-21 18:15:37 +00:00
return res ;
}
2011-06-06 19:15:10 +00:00
/*!
* \brief enable or disable a logging level to a specified console
*/
2008-05-29 21:30:37 +00:00
void ast_console_toggle_loglevel ( int fd , int level , int state )
{
int x ;
2012-04-19 02:40:55 +00:00
if ( level >= NUMLOGLEVELS ) {
level = NUMLOGLEVELS - 1 ;
}
2008-05-29 21:30:37 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
if ( fd == consoles [ x ]. fd ) {
2011-06-06 19:15:10 +00:00
/*
* Since the logging occurs when levels are false, set to
* flipped iinput because this function accepts 0 as off and 1 as on
*/
consoles [ x ]. levels [ level ] = state ? 0 : 1 ;
2008-05-29 21:30:37 +00:00
return ;
}
}
}
2006-05-26 19:48:17 +00:00
/*!
2006-06-08 18:03:08 +00:00
* \brief mute or unmute a console from logging
2006-05-26 19:48:17 +00:00
*/
2012-01-09 17:06:30 +00:00
void ast_console_toggle_mute ( int fd , int silent )
{
2006-05-26 19:48:17 +00:00
int x ;
2006-05-26 21:47:52 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
2006-05-26 19:48:17 +00:00
if ( fd == consoles [ x ]. fd ) {
if ( consoles [ x ]. mute ) {
2006-05-26 21:47:52 +00:00
consoles [ x ]. mute = 0 ;
2007-10-13 05:53:19 +00:00
if ( ! silent )
ast_cli ( fd , "Console is not muted anymore. \n " );
2006-05-26 19:48:17 +00:00
} else {
2006-05-26 21:47:52 +00:00
consoles [ x ]. mute = 1 ;
2007-10-13 05:53:19 +00:00
if ( ! silent )
ast_cli ( fd , "Console is muted. \n " );
2006-05-26 19:48:17 +00:00
}
return ;
}
}
ast_cli ( fd , "Couldn't find remote console. \n " );
}
/*!
2006-06-08 18:03:08 +00:00
* \brief log the string to all attached console clients
2006-05-26 19:48:17 +00:00
*/
2008-05-29 21:30:37 +00:00
static void ast_network_puts_mutable ( const char * string , int level )
2006-05-26 19:48:17 +00:00
{
int x ;
2006-05-26 21:47:52 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
2006-05-26 19:48:17 +00:00
if ( consoles [ x ]. mute )
2006-05-26 21:47:52 +00:00
continue ;
2008-05-29 21:30:37 +00:00
if ( consoles [ x ]. fd > - 1 ) {
2012-03-22 19:51:16 +00:00
if ( ! consoles [ x ]. levels [ level ])
2008-05-29 21:30:37 +00:00
fdprint ( consoles [ x ]. p [ 1 ], string );
}
2006-05-26 19:48:17 +00:00
}
}
/*!
2006-06-08 18:03:08 +00:00
* \brief log the string to the console, and all attached
2006-05-26 19:48:17 +00:00
* console clients
*/
2008-05-29 21:30:37 +00:00
void ast_console_puts_mutable ( const char * string , int level )
2006-05-26 19:48:17 +00:00
{
fputs ( string , stdout );
fflush ( stdout );
2008-05-29 21:30:37 +00:00
ast_network_puts_mutable ( string , level );
2006-05-26 19:48:17 +00:00
}
2005-10-24 20:12:06 +00:00
/*!
2006-06-08 18:03:08 +00:00
* \brief write the string to all attached console clients
2004-01-12 05:05:35 +00:00
*/
static void ast_network_puts ( const char * string )
{
2004-06-29 04:42:19 +00:00
int x ;
2008-02-11 18:27:47 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
2012-03-22 19:51:16 +00:00
if ( consoles [ x ]. fd > - 1 )
2004-06-29 04:42:19 +00:00
fdprint ( consoles [ x ]. p [ 1 ], string );
}
2004-01-12 05:05:35 +00:00
}
2005-10-24 20:12:06 +00:00
/*!
2012-09-21 17:14:59 +00:00
* \brief write the string to the console, and all attached
2004-01-12 05:05:35 +00:00
* console clients
*/
void ast_console_puts ( const char * string )
{
2004-06-29 04:42:19 +00:00
fputs ( string , stdout );
fflush ( stdout );
ast_network_puts ( string );
2004-01-12 05:05:35 +00:00
}
2006-08-08 06:32:04 +00:00
static void network_verboser ( const char * s )
{
2008-05-29 21:30:37 +00:00
ast_network_puts_mutable ( s , __LOG_VERBOSE );
2001-05-09 03:11:22 +00:00
}
static pthread_t lthread ;
2008-12-01 18:52:14 +00:00
/*!
* \brief read() function supporting the reception of user credentials.
*
* \param fd Socket file descriptor.
* \param buffer Receive buffer.
* \param size 'buffer' size.
* \param con Console structure to set received credentials
* \retval -1 on error
* \retval the number of bytes received on success.
*/
static int read_credentials ( int fd , char * buffer , size_t size , struct console * con )
{
#if defined(SO_PEERCRED)
2012-01-13 21:42:12 +00:00
#ifdef HAVE_STRUCT_SOCKPEERCRED_UID
#define HAVE_STRUCT_UCRED_UID
struct sockpeercred cred ;
#else
2008-12-01 18:52:14 +00:00
struct ucred cred ;
2012-01-13 21:42:12 +00:00
#endif
2008-12-01 18:52:14 +00:00
socklen_t len = sizeof ( cred );
#endif
2009-01-14 19:36:57 +00:00
#if defined(HAVE_GETPEEREID)
uid_t uid ;
gid_t gid ;
#else
int uid , gid ;
#endif
int result ;
2008-12-01 18:52:14 +00:00
result = read ( fd , buffer , size );
if ( result < 0 ) {
return result ;
}
2010-11-29 07:30:09 +00:00
#if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
2008-12-01 18:52:14 +00:00
if ( getsockopt ( fd , SOL_SOCKET , SO_PEERCRED , & cred , & len )) {
return result ;
}
2010-11-29 07:30:09 +00:00
#if defined(HAVE_STRUCT_UCRED_UID)
2008-12-01 18:52:14 +00:00
uid = cred . uid ;
gid = cred . gid ;
2010-11-29 07:30:09 +00:00
#else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
uid = cred . cr_uid ;
gid = cred . cr_gid ;
#endif /* defined(HAVE_STRUCT_UCRED_UID) */
2008-12-01 18:52:14 +00:00
#elif defined(HAVE_GETPEEREID)
if ( getpeereid ( fd , & uid , & gid )) {
return result ;
}
#else
return result ;
#endif
con -> uid = uid ;
con -> gid = gid ;
return result ;
}
2001-05-09 03:11:22 +00:00
static void * netconsole ( void * vconsole )
{
struct console * con = vconsole ;
2006-03-31 00:33:28 +00:00
char hostname [ MAXHOSTNAMELEN ] = "" ;
2012-04-19 14:35:56 +00:00
char inbuf [ 512 ];
char outbuf [ 512 ];
2012-04-26 19:33:49 +00:00
const char * const end_buf = inbuf + sizeof ( inbuf );
2012-04-19 14:35:56 +00:00
char * start_read = inbuf ;
2001-05-09 03:11:22 +00:00
int res ;
2004-04-25 20:42:45 +00:00
struct pollfd fds [ 2 ];
2012-03-22 19:51:16 +00:00
2005-05-08 16:44:25 +00:00
if ( gethostname ( hostname , sizeof ( hostname ) - 1 ))
2005-06-05 16:32:16 +00:00
ast_copy_string ( hostname , "<Unknown>" , sizeof ( hostname ));
2012-04-19 14:35:56 +00:00
snprintf ( outbuf , sizeof ( outbuf ), "%s/%ld/%s \n " , hostname , ( long ) ast_mainpid , ast_get_version ());
fdprint ( con -> fd , outbuf );
2007-01-23 00:11:32 +00:00
for (;;) {
2004-04-25 20:42:45 +00:00
fds [ 0 ]. fd = con -> fd ;
fds [ 0 ]. events = POLLIN ;
2005-08-31 22:12:23 +00:00
fds [ 0 ]. revents = 0 ;
2004-04-25 20:42:45 +00:00
fds [ 1 ]. fd = con -> p [ 0 ];
fds [ 1 ]. events = POLLIN ;
2005-08-31 22:12:23 +00:00
fds [ 1 ]. revents = 0 ;
2004-04-25 20:42:45 +00:00
2009-03-18 02:28:55 +00:00
res = ast_poll ( fds , 2 , - 1 );
2001-05-09 03:11:22 +00:00
if ( res < 0 ) {
2004-05-07 14:08:50 +00:00
if ( errno != EINTR )
ast_log ( LOG_WARNING , "poll returned < 0: %s \n " , strerror ( errno ));
2001-05-09 03:11:22 +00:00
continue ;
}
2004-04-25 20:42:45 +00:00
if ( fds [ 0 ]. revents ) {
2012-04-19 14:35:56 +00:00
int cmds_read , bytes_read ;
if (( bytes_read = read_credentials ( con -> fd , start_read , end_buf - start_read , con )) < 1 ) {
2001-05-09 03:11:22 +00:00
break ;
2001-10-11 18:51:39 +00:00
}
2012-04-19 14:35:56 +00:00
/* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
if ( strncmp ( inbuf , "cli quit after " , 15 ) == 0 ) {
ast_cli_command_multiple_full ( con -> uid , con -> gid , con -> fd , bytes_read - 15 , inbuf + 15 );
2008-07-08 20:17:08 +00:00
break ;
}
2012-04-19 14:35:56 +00:00
/* ast_cli_command_multiple_full will only process individual commands terminated by a
* NULL and not trailing partial commands. */
if ( ! ( cmds_read = ast_cli_command_multiple_full ( con -> uid , con -> gid , con -> fd , bytes_read + start_read - inbuf , inbuf ))) {
/* No commands were read. We either have a short read on the first command
* with space left, or a command that is too long */
if ( start_read + bytes_read < end_buf ) {
start_read += bytes_read ;
} else {
ast_log ( LOG_ERROR , "Command too long! Skipping \n " );
start_read = inbuf ;
}
continue ;
}
if ( start_read [ bytes_read - 1 ] == '\0' ) {
/* The read ended on a command boundary, start reading again at the head of inbuf */
start_read = inbuf ;
continue ;
}
/* If we get this far, we have left over characters that have not been processed.
* Advance to the character after the last command read by ast_cli_command_multiple_full.
* We are guaranteed to have at least cmds_read NULLs */
2012-04-24 17:52:26 +00:00
while ( cmds_read -- && ( start_read = strchr ( start_read , '\0' ))) {
2012-04-19 14:35:56 +00:00
start_read ++ ;
}
memmove ( inbuf , start_read , end_buf - start_read );
start_read = end_buf - start_read + inbuf ;
2001-05-09 03:11:22 +00:00
}
2004-04-25 20:42:45 +00:00
if ( fds [ 1 ]. revents ) {
2012-04-19 14:35:56 +00:00
res = read_credentials ( con -> p [ 0 ], outbuf , sizeof ( outbuf ), con );
2001-05-09 03:11:22 +00:00
if ( res < 1 ) {
ast_log ( LOG_ERROR , "read returned %d \n " , res );
break ;
}
2012-04-19 14:35:56 +00:00
res = write ( con -> fd , outbuf , res );
2001-05-09 03:11:22 +00:00
if ( res < 1 )
break ;
}
}
2009-01-13 23:00:27 +00:00
if ( ! ast_opt_hide_connect ) {
ast_verb ( 3 , "Remote UNIX connection disconnected \n " );
}
2001-05-09 03:11:22 +00:00
close ( con -> fd );
close ( con -> p [ 0 ]);
close ( con -> p [ 1 ]);
con -> fd = - 1 ;
2012-03-22 19:51:16 +00:00
2001-05-09 03:11:22 +00:00
return NULL ;
}
static void * listener ( void * unused )
{
2004-12-14 23:36:30 +00:00
struct sockaddr_un sunaddr ;
2001-05-09 03:11:22 +00:00
int s ;
2005-05-15 03:21:51 +00:00
socklen_t len ;
2001-05-09 03:11:22 +00:00
int x ;
2001-10-11 18:51:39 +00:00
int flags ;
2004-04-25 20:42:45 +00:00
struct pollfd fds [ 1 ];
2006-03-31 00:33:28 +00:00
for (;;) {
2002-09-12 03:22:07 +00:00
if ( ast_socket < 0 )
return NULL ;
2004-04-25 20:42:45 +00:00
fds [ 0 ]. fd = ast_socket ;
2006-03-31 00:33:28 +00:00
fds [ 0 ]. events = POLLIN ;
2009-03-18 02:28:55 +00:00
s = ast_poll ( fds , 1 , - 1 );
2006-07-03 05:14:06 +00:00
pthread_testcancel ();
2003-09-29 20:20:04 +00:00
if ( s < 0 ) {
2004-03-04 21:32:32 +00:00
if ( errno != EINTR )
2004-04-25 20:42:45 +00:00
ast_log ( LOG_WARNING , "poll returned error: %s \n " , strerror ( errno ));
2003-09-29 20:20:04 +00:00
continue ;
}
2004-12-14 23:36:30 +00:00
len = sizeof ( sunaddr );
s = accept ( ast_socket , ( struct sockaddr * ) & sunaddr , & len );
2001-05-09 03:11:22 +00:00
if ( s < 0 ) {
2004-03-02 16:58:17 +00:00
if ( errno != EINTR )
2004-03-03 00:05:00 +00:00
ast_log ( LOG_WARNING , "Accept returned %d: %s \n " , s , strerror ( errno ));
2001-05-09 03:11:22 +00:00
} else {
2008-12-01 18:52:14 +00:00
#if !defined(SO_PASSCRED)
{
#else
int sckopt = 1 ;
/* turn on socket credentials passing. */
if ( setsockopt ( s , SOL_SOCKET , SO_PASSCRED , & sckopt , sizeof ( sckopt )) < 0 ) {
ast_log ( LOG_WARNING , "Unable to turn on socket credentials passing \n " );
} else {
#endif
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
if ( consoles [ x ]. fd >= 0 ) {
continue ;
}
2001-10-11 18:51:39 +00:00
if ( socketpair ( AF_LOCAL , SOCK_STREAM , 0 , consoles [ x ]. p )) {
2001-05-09 03:11:22 +00:00
ast_log ( LOG_ERROR , "Unable to create pipe: %s \n " , strerror ( errno ));
consoles [ x ]. fd = - 1 ;
fdprint ( s , "Server failed to create pipe \n " );
close ( s );
break ;
}
2001-10-11 18:51:39 +00:00
flags = fcntl ( consoles [ x ]. p [ 1 ], F_GETFL );
fcntl ( consoles [ x ]. p [ 1 ], F_SETFL , flags | O_NONBLOCK );
2001-05-09 03:11:22 +00:00
consoles [ x ]. fd = s ;
2007-10-13 05:53:19 +00:00
consoles [ x ]. mute = 1 ; /* Default is muted, we will un-mute if necessary */
2008-12-01 18:52:14 +00:00
/* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
to know if the user didn't send the credentials. */
consoles [ x ]. uid = - 2 ;
consoles [ x ]. gid = - 2 ;
2007-05-24 18:30:19 +00:00
if ( ast_pthread_create_detached_background ( & consoles [ x ]. t , NULL , netconsole , & consoles [ x ])) {
2004-05-07 14:08:50 +00:00
ast_log ( LOG_ERROR , "Unable to spawn thread to handle connection: %s \n " , strerror ( errno ));
2006-04-11 21:58:44 +00:00
close ( consoles [ x ]. p [ 0 ]);
close ( consoles [ x ]. p [ 1 ]);
2001-05-09 03:11:22 +00:00
consoles [ x ]. fd = - 1 ;
fdprint ( s , "Server failed to spawn thread \n " );
close ( s );
}
break ;
}
2008-12-01 18:52:14 +00:00
if ( x >= AST_MAX_CONNECTS ) {
fdprint ( s , "No more connections allowed \n " );
ast_log ( LOG_WARNING , "No more connections allowed \n " );
close ( s );
2009-01-13 23:00:27 +00:00
} else if (( consoles [ x ]. fd > - 1 ) && ( ! ast_opt_hide_connect )) {
2008-12-01 18:52:14 +00:00
ast_verb ( 3 , "Remote UNIX connection \n " );
2009-01-13 23:00:27 +00:00
}
2001-05-09 03:11:22 +00:00
}
}
}
return NULL ;
}
static int ast_makesocket ( void )
{
2004-12-14 23:36:30 +00:00
struct sockaddr_un sunaddr ;
2001-05-09 03:11:22 +00:00
int res ;
int x ;
2005-07-25 23:09:13 +00:00
uid_t uid = - 1 ;
gid_t gid = - 1 ;
2005-02-11 21:16:34 +00:00
2012-03-22 19:51:16 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ )
2001-05-09 03:11:22 +00:00
consoles [ x ]. fd = - 1 ;
2005-07-25 23:09:13 +00:00
unlink ( ast_config_AST_SOCKET );
2001-05-09 03:11:22 +00:00
ast_socket = socket ( PF_LOCAL , SOCK_STREAM , 0 );
if ( ast_socket < 0 ) {
ast_log ( LOG_WARNING , "Unable to create control socket: %s \n " , strerror ( errno ));
return - 1 ;
2012-03-22 19:51:16 +00:00
}
2004-12-14 23:36:30 +00:00
memset ( & sunaddr , 0 , sizeof ( sunaddr ));
sunaddr . sun_family = AF_LOCAL ;
2005-07-25 23:09:13 +00:00
ast_copy_string ( sunaddr . sun_path , ast_config_AST_SOCKET , sizeof ( sunaddr . sun_path ));
2004-12-14 23:36:30 +00:00
res = bind ( ast_socket , ( struct sockaddr * ) & sunaddr , sizeof ( sunaddr ));
2001-05-09 03:11:22 +00:00
if ( res ) {
2005-07-25 23:09:13 +00:00
ast_log ( LOG_WARNING , "Unable to bind socket to %s: %s \n " , ast_config_AST_SOCKET , strerror ( errno ));
2001-05-09 03:11:22 +00:00
close ( ast_socket );
ast_socket = - 1 ;
return - 1 ;
}
res = listen ( ast_socket , 2 );
if ( res < 0 ) {
2005-07-25 23:09:13 +00:00
ast_log ( LOG_WARNING , "Unable to listen on socket %s: %s \n " , ast_config_AST_SOCKET , strerror ( errno ));
2001-05-09 03:11:22 +00:00
close ( ast_socket );
ast_socket = - 1 ;
return - 1 ;
}
2008-05-02 02:33:04 +00:00
if ( ast_register_verbose ( network_verboser )) {
ast_log ( LOG_WARNING , "Unable to register network verboser? \n " );
}
2012-05-10 18:35:14 +00:00
if ( ast_pthread_create_background ( & lthread , NULL , listener , NULL )) {
ast_log ( LOG_WARNING , "Unable to create listener thread. \n " );
close ( ast_socket );
return - 1 ;
}
2005-02-11 21:16:34 +00:00
2005-07-25 23:09:13 +00:00
if ( ! ast_strlen_zero ( ast_config_AST_CTL_OWNER )) {
2005-02-11 21:16:34 +00:00
struct passwd * pw ;
2006-10-29 20:47:01 +00:00
if (( pw = getpwnam ( ast_config_AST_CTL_OWNER )) == NULL )
2005-07-25 23:09:13 +00:00
ast_log ( LOG_WARNING , "Unable to find uid of user %s \n " , ast_config_AST_CTL_OWNER );
2006-10-29 20:47:01 +00:00
else
2005-07-25 23:09:13 +00:00
uid = pw -> pw_uid ;
2005-02-11 21:16:34 +00:00
}
2012-03-22 19:51:16 +00:00
2005-07-25 23:09:13 +00:00
if ( ! ast_strlen_zero ( ast_config_AST_CTL_GROUP )) {
2005-02-11 21:16:34 +00:00
struct group * grp ;
2006-10-29 20:47:01 +00:00
if (( grp = getgrnam ( ast_config_AST_CTL_GROUP )) == NULL )
2005-07-25 23:09:13 +00:00
ast_log ( LOG_WARNING , "Unable to find gid of group %s \n " , ast_config_AST_CTL_GROUP );
2006-10-29 20:47:01 +00:00
else
2005-07-25 23:09:13 +00:00
gid = grp -> gr_gid ;
2005-02-11 21:16:34 +00:00
}
2005-07-25 23:09:13 +00:00
if ( chown ( ast_config_AST_SOCKET , uid , gid ) < 0 )
ast_log ( LOG_WARNING , "Unable to change ownership of %s: %s \n " , ast_config_AST_SOCKET , strerror ( errno ));
if ( ! ast_strlen_zero ( ast_config_AST_CTL_PERMISSIONS )) {
2005-12-26 18:35:28 +00:00
int p1 ;
2005-02-11 21:16:34 +00:00
mode_t p ;
2009-08-10 19:20:57 +00:00
sscanf ( ast_config_AST_CTL_PERMISSIONS , "%30o" , & p1 );
2005-12-26 18:35:28 +00:00
p = p1 ;
2005-07-25 23:09:13 +00:00
if (( chmod ( ast_config_AST_SOCKET , p )) < 0 )
ast_log ( LOG_WARNING , "Unable to change file permissions of %s: %s \n " , ast_config_AST_SOCKET , strerror ( errno ));
2005-02-11 21:16:34 +00:00
}
2001-05-09 03:11:22 +00:00
return 0 ;
}
static int ast_tryconnect ( void )
{
2004-12-14 23:36:30 +00:00
struct sockaddr_un sunaddr ;
2001-05-09 03:11:22 +00:00
int res ;
ast_consock = socket ( PF_LOCAL , SOCK_STREAM , 0 );
if ( ast_consock < 0 ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to create socket: %s \n " , strerror ( errno ));
2001-05-09 03:11:22 +00:00
return 0 ;
}
2004-12-14 23:36:30 +00:00
memset ( & sunaddr , 0 , sizeof ( sunaddr ));
sunaddr . sun_family = AF_LOCAL ;
2007-12-18 09:46:18 +00:00
ast_copy_string ( sunaddr . sun_path , ast_config_AST_SOCKET , sizeof ( sunaddr . sun_path ));
2004-12-14 23:36:30 +00:00
res = connect ( ast_consock , ( struct sockaddr * ) & sunaddr , sizeof ( sunaddr ));
2001-05-09 03:11:22 +00:00
if ( res ) {
close ( ast_consock );
ast_consock = - 1 ;
return 0 ;
} else
return 1 ;
}
2006-06-08 18:03:08 +00:00
/*! \brief Urgent handler
2012-09-21 17:14:59 +00:00
*
* Called by soft_hangup to interrupt the poll, read, or other
* system call. We don't actually need to do anything though.
* Remember: Cannot EVER ast_log from within a signal handler
2005-10-24 20:12:06 +00:00
*/
2010-05-26 21:17:46 +00:00
static void _urg_handler ( int num )
1999-11-15 04:57:28 +00:00
{
return ;
}
2010-05-26 21:17:46 +00:00
static struct sigaction urg_handler = {
. sa_handler = _urg_handler ,
2010-06-10 08:15:45 +00:00
. sa_flags = SA_RESTART ,
2010-05-26 21:17:46 +00:00
};
static void _hup_handler ( int num )
2001-05-09 03:11:22 +00:00
{
2011-06-27 16:32:19 +00:00
int a = 0 , save_errno = errno ;
2012-02-14 20:27:16 +00:00
printf ( "Received HUP signal -- Reloading configs \n " );
2004-02-23 03:43:21 +00:00
if ( restartnow )
execvp ( _argv [ 0 ], _argv );
2007-02-23 23:25:22 +00:00
sig_flags . need_reload = 1 ;
2008-11-02 18:52:13 +00:00
if ( sig_alert_pipe [ 1 ] != - 1 ) {
if ( write ( sig_alert_pipe [ 1 ], & a , sizeof ( a )) < 0 ) {
fprintf ( stderr , "hup_handler: write() failed: %s \n " , strerror ( errno ));
}
}
2011-06-27 16:32:19 +00:00
errno = save_errno ;
2001-05-09 03:11:22 +00:00
}
2010-05-26 21:17:46 +00:00
static struct sigaction hup_handler = {
. sa_handler = _hup_handler ,
2010-06-10 08:15:45 +00:00
. sa_flags = SA_RESTART ,
2010-05-26 21:17:46 +00:00
};
static void _child_handler ( int sig )
2001-05-09 03:11:22 +00:00
{
2003-12-01 02:47:19 +00:00
/* Must not ever ast_log or ast_verbose within signal handler */
2011-06-27 16:32:19 +00:00
int n , status , save_errno = errno ;
2003-09-16 19:35:57 +00:00
/*
* Reap all dead children -- not just one
*/
for ( n = 0 ; wait4 ( - 1 , & status , WNOHANG , NULL ) > 0 ; n ++ )
;
2012-03-22 19:51:16 +00:00
if ( n == 0 && option_debug )
2003-12-01 02:47:19 +00:00
printf ( "Huh? Child handler, but nobody there? \n " );
2011-06-27 16:32:19 +00:00
errno = save_errno ;
2001-05-09 03:11:22 +00:00
}
2003-09-16 19:35:57 +00:00
2010-05-26 21:17:46 +00:00
static struct sigaction child_handler = {
. sa_handler = _child_handler ,
2010-06-10 08:15:45 +00:00
. sa_flags = SA_RESTART ,
2010-05-26 21:17:46 +00:00
};
2006-11-22 17:41:07 +00:00
/*! \brief Set maximum open files */
static void set_ulimit ( int value )
{
struct rlimit l = { 0 , 0 };
2012-03-22 19:51:16 +00:00
2006-11-22 17:41:07 +00:00
if ( value <= 0 ) {
ast_log ( LOG_WARNING , "Unable to change max files open to invalid value %i \n " , value );
return ;
}
2012-03-22 19:51:16 +00:00
2006-11-22 17:41:07 +00:00
l . rlim_cur = value ;
l . rlim_max = value ;
2012-03-22 19:51:16 +00:00
2006-11-22 17:41:07 +00:00
if ( setrlimit ( RLIMIT_NOFILE , & l )) {
ast_log ( LOG_WARNING , "Unable to disable core size resource limit: %s \n " , strerror ( errno ));
return ;
}
2012-03-22 19:51:16 +00:00
2006-11-22 17:41:07 +00:00
ast_log ( LOG_NOTICE , "Setting max files open to %d \n " , value );
2012-03-22 19:51:16 +00:00
2006-11-22 17:41:07 +00:00
return ;
}
2006-06-08 18:03:08 +00:00
/*! \brief Set an X-term or screen title */
2000-10-25 23:22:50 +00:00
static void set_title ( char * text )
{
if ( getenv ( "TERM" ) && strstr ( getenv ( "TERM" ), "xterm" ))
fprintf ( stdout , " \033 ]2;%s \007 " , text );
}
static void set_icon ( char * text )
{
if ( getenv ( "TERM" ) && strstr ( getenv ( "TERM" ), "xterm" ))
fprintf ( stdout , " \033 ]1;%s \007 " , text );
}
2012-09-21 17:14:59 +00:00
/*! \brief We set ourselves to a high priority, that we might pre-empt
* everything else. If your PBX has heavy activity on it, this is a
* good thing.
*/
2005-08-23 01:30:22 +00:00
int ast_set_priority ( int pri )
1999-12-19 22:38:55 +00:00
{
struct sched_param sched ;
2001-03-22 04:14:04 +00:00
memset ( & sched , 0 , sizeof ( sched ));
2003-04-23 20:22:14 +00:00
#ifdef __linux__
2012-03-22 19:51:16 +00:00
if ( pri ) {
2001-03-22 04:14:04 +00:00
sched . sched_priority = 10 ;
if ( sched_setscheduler ( 0 , SCHED_RR , & sched )) {
1999-12-19 22:38:55 +00:00
ast_log ( LOG_WARNING , "Unable to set high priority \n " );
return - 1 ;
2001-03-22 04:14:04 +00:00
} else
2012-02-14 20:27:16 +00:00
ast_verb ( 1 , "Set to realtime thread \n " );
1999-12-19 22:38:55 +00:00
} else {
sched . sched_priority = 0 ;
2007-04-09 03:04:07 +00:00
/* According to the manpage, these parameters can never fail. */
sched_setscheduler ( 0 , SCHED_OTHER , & sched );
1999-12-19 22:38:55 +00:00
}
2003-04-23 20:22:14 +00:00
#else
if ( pri ) {
if ( setpriority ( PRIO_PROCESS , 0 , - 10 ) == - 1 ) {
ast_log ( LOG_WARNING , "Unable to set high priority \n " );
return - 1 ;
} else
2012-02-14 20:27:16 +00:00
ast_verb ( 1 , "Set to high priority \n " );
2003-04-23 20:22:14 +00:00
} else {
2007-04-09 03:04:07 +00:00
/* According to the manpage, these parameters can never fail. */
setpriority ( PRIO_PROCESS , 0 , 0 );
2003-04-23 20:22:14 +00:00
}
#endif
1999-12-19 22:38:55 +00:00
return 0 ;
}
2012-01-15 20:16:08 +00:00
static int can_safely_quit ( shutdown_nice_t niceness , int restart );
static void really_quit ( int num , shutdown_nice_t niceness , int restart );
static void quit_handler ( int num , shutdown_nice_t niceness , int restart )
1999-11-15 04:57:28 +00:00
{
2012-01-15 20:16:08 +00:00
if ( can_safely_quit ( niceness , restart )) {
really_quit ( num , niceness , restart );
/* No one gets here. */
}
/* It wasn't our time. */
}
static int can_safely_quit ( shutdown_nice_t niceness , int restart )
{
/* Check if someone else isn't already doing this. */
ast_mutex_lock ( & safe_system_lock );
if ( shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown ) {
/* Already in progress and other request was less nice. */
ast_mutex_unlock ( & safe_system_lock );
ast_verbose ( "Ignoring asterisk %s request, already in progress. \n " , restart ? "restart" : "shutdown" );
return 0 ;
}
shuttingdown = niceness ;
ast_mutex_unlock ( & safe_system_lock );
/* Try to get as many CDRs as possible submitted to the backend engines
* (if in batch mode). really_quit happens to call it again when running
* the atexit handlers, otherwise this would be a bit early. */
2005-06-03 01:42:31 +00:00
ast_cdr_engine_term ();
2012-10-02 01:47:16 +00:00
/* Shutdown the message queue for the technology agnostic message channel.
* This has to occur before we pause shutdown pending ast_undestroyed_channels. */
2012-09-11 21:17:53 +00:00
ast_msg_shutdown ();
2012-01-15 20:16:08 +00:00
if ( niceness == SHUTDOWN_NORMAL ) {
time_t s , e ;
/* Begin shutdown routine, hanging up active channels */
ast_begin_shutdown ( 1 );
if ( option_verbose && ast_opt_console ) {
ast_verbose ( "Beginning asterisk %s.... \n " , restart ? "restart" : "shutdown" );
}
time ( & s );
for (;;) {
time ( & e );
/* Wait up to 15 seconds for all channels to go away */
2012-05-22 17:29:12 +00:00
if (( e - s ) > 15 || ! ast_undestroyed_channels () || shuttingdown != niceness ) {
2012-01-15 20:16:08 +00:00
break ;
2002-05-14 14:43:52 +00:00
}
2012-01-15 20:16:08 +00:00
/* Sleep 1/10 of a second */
usleep ( 100000 );
}
} else if ( niceness >= SHUTDOWN_NICE ) {
if ( niceness != SHUTDOWN_REALLY_NICE ) {
ast_begin_shutdown ( 0 );
}
if ( option_verbose && ast_opt_console ) {
2012-02-14 20:27:16 +00:00
ast_verb ( 0 , "Waiting for inactivity to perform %s... \n " , restart ? "restart" : "halt" );
2012-01-15 20:16:08 +00:00
}
for (;;) {
2012-05-22 17:29:12 +00:00
if ( ! ast_undestroyed_channels () || shuttingdown != niceness ) {
2012-01-15 20:16:08 +00:00
break ;
2002-05-14 14:43:52 +00:00
}
2012-01-15 20:16:08 +00:00
sleep ( 1 );
2002-05-14 14:43:52 +00:00
}
2012-01-15 20:16:08 +00:00
}
2002-05-14 14:43:52 +00:00
2012-01-15 20:16:08 +00:00
/* Re-acquire lock and check if someone changed the niceness, in which
2012-09-21 17:14:59 +00:00
* case someone else has taken over the shutdown.
*/
2012-01-15 20:16:08 +00:00
ast_mutex_lock ( & safe_system_lock );
if ( shuttingdown != niceness ) {
if ( shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console ) {
2012-02-14 20:27:16 +00:00
ast_verb ( 0 , "Asterisk %s cancelled. \n " , restart ? "restart" : "shutdown" );
2002-05-14 14:43:52 +00:00
}
2012-01-15 20:16:08 +00:00
ast_mutex_unlock ( & safe_system_lock );
return 0 ;
}
shuttingdown = SHUTTING_DOWN ;
ast_mutex_unlock ( & safe_system_lock );
return 1 ;
}
2007-06-05 15:54:36 +00:00
2012-12-03 23:00:08 +00:00
/*! Called when exiting is certain. */
2012-01-15 20:16:08 +00:00
static void really_quit ( int num , shutdown_nice_t niceness , int restart )
{
2012-12-03 20:46:11 +00:00
int active_channels ;
2012-01-15 20:16:08 +00:00
if ( niceness >= SHUTDOWN_NICE ) {
ast_module_shutdown ();
2002-05-14 14:43:52 +00:00
}
2012-01-15 20:16:08 +00:00
2008-11-05 22:19:18 +00:00
if ( ast_opt_console || ( ast_opt_remote && ! ast_opt_exec )) {
2012-01-15 20:16:08 +00:00
char filename [ 80 ] = "" ;
2010-07-23 16:43:34 +00:00
if ( getenv ( "HOME" )) {
2001-05-09 03:11:22 +00:00
snprintf ( filename , sizeof ( filename ), "%s/.asterisk_history" , getenv ( "HOME" ));
2010-07-23 16:43:34 +00:00
}
if ( ! ast_strlen_zero ( filename )) {
2003-02-06 06:15:25 +00:00
ast_el_write_history ( filename );
2010-07-23 16:43:34 +00:00
}
2011-07-18 12:54:29 +00:00
if ( consolethread == AST_PTHREADT_NULL || consolethread == pthread_self ()) {
/* Only end if we are the consolethread, otherwise there's a race with that thread. */
2010-07-23 16:43:34 +00:00
if ( el != NULL ) {
el_end ( el );
}
if ( el_hist != NULL ) {
history_end ( el_hist );
}
2011-07-18 12:54:29 +00:00
} else if ( mon_sig_flags == pthread_self ()) {
if ( consolethread != AST_PTHREADT_NULL ) {
pthread_kill ( consolethread , SIGURG );
}
2010-07-23 16:43:34 +00:00
}
2001-05-09 03:11:22 +00:00
}
2012-12-03 20:46:11 +00:00
active_channels = ast_active_channels ();
2012-10-02 21:26:27 +00:00
/* The manager event for shutdown must happen prior to ast_run_atexits, as
* the manager interface will dispose of its sessions as part of its
* shutdown.
*/
2012-07-10 22:26:27 +00:00
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
<syntax>
<parameter name="Shutdown">
<enumlist>
<enum name="Uncleanly"/>
<enum name="Cleanly"/>
</enumlist>
</parameter>
<parameter name="Restart">
<enumlist>
<enum name="True"/>
<enum name="False"/>
</enumlist>
</parameter>
</syntax>
</managerEventInstance>
***/
2012-10-02 21:26:27 +00:00
manager_event ( EVENT_FLAG_SYSTEM , "Shutdown" , "Shutdown: %s \r\n "
"Restart: %s \r\n " ,
2012-12-03 20:46:11 +00:00
active_channels ? "Uncleanly" : "Cleanly" ,
2012-10-02 21:26:27 +00:00
restart ? "True" : "False" );
2012-12-03 23:00:08 +00:00
ast_verb ( 0 , "Asterisk %s ending (%d). \n " ,
active_channels ? "uncleanly" : "cleanly" , num );
2012-10-02 21:26:27 +00:00
ast_verb ( 0 , "Executing last minute cleanups \n " );
ast_run_atexits ();
2012-12-03 23:00:08 +00:00
2012-10-02 21:26:27 +00:00
ast_debug ( 1 , "Asterisk ending (%d). \n " , num );
2002-09-12 03:22:07 +00:00
if ( ast_socket > - 1 ) {
2006-07-03 05:14:06 +00:00
pthread_cancel ( lthread );
2001-05-09 03:11:22 +00:00
close ( ast_socket );
2002-09-12 03:22:07 +00:00
ast_socket = - 1 ;
2006-03-25 23:22:44 +00:00
unlink ( ast_config_AST_SOCKET );
2002-09-12 03:22:07 +00:00
}
2001-05-09 03:11:22 +00:00
if ( ast_consock > - 1 )
close ( ast_consock );
2005-12-04 20:40:46 +00:00
if ( ! ast_opt_remote )
unlink ( ast_config_AST_PID );
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2002-05-14 14:43:52 +00:00
if ( restart ) {
2012-01-15 20:16:08 +00:00
int i ;
2012-02-14 20:27:16 +00:00
ast_verb ( 0 , "Preparing for Asterisk restart... \n " );
2002-05-14 14:43:52 +00:00
/* Mark all FD's for closing on exec */
2012-01-15 20:16:08 +00:00
for ( i = 3 ; i < 32768 ; i ++ ) {
fcntl ( i , F_SETFD , FD_CLOEXEC );
2002-05-14 14:43:52 +00:00
}
2012-02-14 20:27:16 +00:00
ast_verb ( 0 , "Asterisk is now restarting... \n " );
2004-02-23 03:43:21 +00:00
restartnow = 1 ;
2004-06-17 01:13:10 +00:00
/* close logger */
close_logger ();
2012-12-03 20:46:11 +00:00
clean_time_zones ();
2004-06-17 01:13:10 +00:00
2012-03-22 19:51:16 +00:00
/* If there is a consolethread running send it a SIGHUP
2004-02-23 03:43:21 +00:00
so it can execvp, otherwise we can do it ourselves */
2005-09-25 16:52:04 +00:00
if (( consolethread != AST_PTHREADT_NULL ) && ( consolethread != pthread_self ())) {
2004-02-23 03:43:21 +00:00
pthread_kill ( consolethread , SIGHUP );
2004-03-02 23:50:03 +00:00
/* Give the signal handler some time to complete */
sleep ( 2 );
} else
2004-02-23 03:43:21 +00:00
execvp ( _argv [ 0 ], _argv );
2012-03-22 19:51:16 +00:00
2004-06-17 01:13:10 +00:00
} else {
/* close logger */
close_logger ();
2012-12-03 20:46:11 +00:00
clean_time_zones ();
2003-08-07 03:48:00 +00:00
}
2012-01-15 20:16:08 +00:00
2003-08-07 03:48:00 +00:00
exit ( 0 );
2002-05-14 14:43:52 +00:00
}
static void __quit_handler ( int num )
{
2007-02-23 23:25:22 +00:00
int a = 0 ;
sig_flags . need_quit = 1 ;
2008-11-02 18:52:13 +00:00
if ( sig_alert_pipe [ 1 ] != - 1 ) {
if ( write ( sig_alert_pipe [ 1 ], & a , sizeof ( a )) < 0 ) {
2010-05-26 21:17:46 +00:00
fprintf ( stderr , "quit_handler: write() failed: %s \n " , strerror ( errno ));
2008-11-02 18:52:13 +00:00
}
}
2007-02-23 23:25:22 +00:00
/* There is no need to restore the signal handler here, since the app
* is going to exit */
1999-11-15 04:57:28 +00:00
}
2008-12-11 23:38:56 +00:00
static void __remote_quit_handler ( int num )
{
sig_flags . need_quit = 1 ;
}
2003-06-27 23:02:52 +00:00
static const char * fix_header ( char * outbuf , int maxout , const char * s , char * cmp )
2002-05-14 14:43:52 +00:00
{
2003-06-27 23:02:52 +00:00
const char * c ;
2008-05-05 23:00:31 +00:00
2003-06-27 23:02:52 +00:00
if ( ! strncmp ( s , cmp , strlen ( cmp ))) {
c = s + strlen ( cmp );
2002-05-14 14:43:52 +00:00
term_color ( outbuf , cmp , COLOR_GRAY , 0 , maxout );
2003-06-27 23:02:52 +00:00
return c ;
2002-05-14 14:43:52 +00:00
}
2003-06-27 23:02:52 +00:00
return NULL ;
2002-05-14 14:43:52 +00:00
}
2012-02-14 20:27:16 +00:00
/* These gymnastics are due to platforms which designate char as unsigned by
* default. Level is the negative character -- offset by 1, because \0 is the
* EOS delimiter. */
#define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
#define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
2006-08-08 06:32:04 +00:00
static void console_verboser ( const char * s )
1999-12-19 22:38:55 +00:00
{
2002-05-14 14:43:52 +00:00
char tmp [ 80 ];
2006-03-31 00:33:28 +00:00
const char * c = NULL ;
2012-02-14 20:27:16 +00:00
char level = 0 ;
if ( VERBOSE_HASMAGIC ( s )) {
level = VERBOSE_MAGIC2LEVEL ( s );
s ++ ;
if ( level > option_verbose ) {
return ;
}
}
2006-08-08 06:32:04 +00:00
if (( c = fix_header ( tmp , sizeof ( tmp ), s , VERBOSE_PREFIX_4 )) ||
( c = fix_header ( tmp , sizeof ( tmp ), s , VERBOSE_PREFIX_3 )) ||
( c = fix_header ( tmp , sizeof ( tmp ), s , VERBOSE_PREFIX_2 )) ||
( c = fix_header ( tmp , sizeof ( tmp ), s , VERBOSE_PREFIX_1 ))) {
fputs ( tmp , stdout );
fputs ( c , stdout );
2008-05-21 18:12:19 +00:00
} else {
2006-08-08 06:32:04 +00:00
fputs ( s , stdout );
2008-05-21 18:12:19 +00:00
}
2006-08-08 06:32:04 +00:00
2000-01-02 20:59:00 +00:00
fflush ( stdout );
2012-02-14 20:27:16 +00:00
2006-08-08 06:32:04 +00:00
/* Wake up a poll()ing console */
2011-11-29 18:43:16 +00:00
if ( ast_opt_console && consolethread != AST_PTHREADT_NULL ) {
2006-08-08 06:32:04 +00:00
pthread_kill ( consolethread , SIGURG );
2011-11-29 18:43:16 +00:00
}
1999-12-19 22:38:55 +00:00
}
2004-08-01 18:12:52 +00:00
static int ast_all_zeros ( char * s )
{
2006-03-31 00:33:28 +00:00
while ( * s ) {
2004-08-01 18:12:52 +00:00
if ( * s > 32 )
return 0 ;
2012-03-22 19:51:16 +00:00
s ++ ;
2004-08-01 18:12:52 +00:00
}
return 1 ;
}
1999-12-19 22:38:55 +00:00
static void consolehandler ( char * s )
{
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_end ());
2002-05-14 14:43:52 +00:00
fflush ( stdout );
2006-07-12 14:04:16 +00:00
1999-12-19 22:38:55 +00:00
/* Called when readline data is available */
2006-07-12 14:04:16 +00:00
if ( ! ast_all_zeros ( s ))
2003-02-06 06:15:25 +00:00
ast_el_add_history ( s );
2006-07-12 14:04:16 +00:00
/* The real handler for bang */
if ( s [ 0 ] == '!' ) {
if ( s [ 1 ])
ast_safe_system ( s + 1 );
else
ast_safe_system ( getenv ( "SHELL" ) ? getenv ( "SHELL" ) : "/bin/sh" );
2012-03-22 19:51:16 +00:00
} else
1999-12-19 22:38:55 +00:00
ast_cli_command ( STDOUT_FILENO , s );
}
2003-02-06 06:15:25 +00:00
static int remoteconsolehandler ( char * s )
2001-05-09 03:11:22 +00:00
{
2003-02-06 06:15:25 +00:00
int ret = 0 ;
2006-07-12 14:04:16 +00:00
2001-05-09 03:11:22 +00:00
/* Called when readline data is available */
2006-07-12 14:04:16 +00:00
if ( ! ast_all_zeros ( s ))
2003-02-06 06:15:25 +00:00
ast_el_add_history ( s );
2006-07-12 14:04:16 +00:00
/* The real handler for bang */
if ( s [ 0 ] == '!' ) {
if ( s [ 1 ])
ast_safe_system ( s + 1 );
else
ast_safe_system ( getenv ( "SHELL" ) ? getenv ( "SHELL" ) : "/bin/sh" );
ret = 1 ;
2012-02-14 20:27:16 +00:00
} else if ( strncasecmp ( s , "core set verbose " , 17 ) == 0 ) {
int old_verbose = option_verbose ;
if ( strncasecmp ( s + 17 , "atleast " , 8 ) == 0 ) {
int tmp ;
if ( sscanf ( s + 25 , "%d" , & tmp ) != 1 ) {
fprintf ( stderr , "Usage: core set verbose [atleast] <level> \n " );
} else {
if ( tmp > option_verbose ) {
option_verbose = tmp ;
}
if ( old_verbose != option_verbose ) {
fprintf ( stdout , "Set remote console verbosity from %d to %d \n " , old_verbose , option_verbose );
} else {
fprintf ( stdout , "Verbosity level unchanged. \n " );
}
}
} else {
if ( sscanf ( s + 17 , "%d" , & option_verbose ) != 1 ) {
fprintf ( stderr , "Usage: core set verbose [atleast] <level> \n " );
} else {
if ( old_verbose != option_verbose ) {
fprintf ( stdout , "Set remote console verbosity to %d \n " , option_verbose );
} else {
fprintf ( stdout , "Verbosity level unchanged. \n " );
}
}
}
ret = 1 ;
} else if (( strncasecmp ( s , "quit" , 4 ) == 0 || strncasecmp ( s , "exit" , 4 ) == 0 ) &&
2006-07-12 14:04:16 +00:00
( s [ 4 ] == '\0' || isspace ( s [ 4 ]))) {
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_FAST , 0 );
2006-07-12 14:04:16 +00:00
ret = 1 ;
}
2003-02-06 06:15:25 +00:00
return ret ;
2001-05-09 03:11:22 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_version ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-04-29 00:15:28 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "core show version" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2007-10-11 19:03:06 +00:00
"Usage: core show version \n "
" Shows Asterisk version information. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( a -> argc != 3 )
return CLI_SHOWUSAGE ;
ast_cli ( a -> fd , "Asterisk %s built by %s @ %s on a %s running %s on %s \n " ,
2008-01-05 22:09:06 +00:00
ast_get_version (), ast_build_user , ast_build_hostname ,
2006-04-29 00:15:28 +00:00
ast_build_machine , ast_build_os , ast_build_date );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2006-04-29 00:15:28 +00:00
}
2003-03-16 22:37:31 +00:00
#if 0
1999-12-19 22:38:55 +00:00
static int handle_quit(int fd, int argc, char *argv[])
{
if (argc != 1)
return RESULT_SHOWUSAGE;
2012-01-15 20:16:08 +00:00
quit_handler(0, SHUTDOWN_NORMAL, 0);
2002-05-14 14:43:52 +00:00
return RESULT_SUCCESS;
}
2003-03-16 22:37:31 +00:00
#endif
2002-05-14 14:43:52 +00:00
2007-10-11 19:03:06 +00:00
static char * handle_stop_now ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2002-05-14 14:43:52 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e -> command = "core stop now" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2008-02-08 21:26:32 +00:00
"Usage: core stop now \n "
2007-10-11 19:03:06 +00:00
" Shuts down a running Asterisk immediately, hanging up all active calls . \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
if ( a -> argc != e -> args )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_NORMAL , 0 /* not restart */ );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2002-05-14 14:43:52 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_stop_gracefully ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2002-05-14 14:43:52 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e -> command = "core stop gracefully" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2008-02-08 21:26:32 +00:00
"Usage: core stop gracefully \n "
2007-10-11 19:03:06 +00:00
" Causes Asterisk to not accept new calls, and exit when all \n "
" active calls have terminated normally. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
if ( a -> argc != e -> args )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_NICE , 0 /* no restart */ );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2002-05-14 14:43:52 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_stop_when_convenient ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2003-04-23 16:24:09 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e -> command = "core stop when convenient" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2008-02-08 21:26:32 +00:00
"Usage: core stop when convenient \n "
2007-10-11 19:03:06 +00:00
" Causes Asterisk to perform a shutdown when all active calls have ended. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
if ( a -> argc != e -> args )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
ast_cli ( a -> fd , "Waiting for inactivity to perform halt \n " );
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_REALLY_NICE , 0 /* don't restart */ );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2003-04-23 16:24:09 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_restart_now ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2002-05-14 14:43:52 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e -> command = "core restart now" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2008-02-08 21:26:32 +00:00
"Usage: core restart now \n "
2007-10-11 19:03:06 +00:00
" Causes Asterisk to hangup all calls and exec() itself performing a cold \n "
" restart. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
if ( a -> argc != e -> args )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_NORMAL , 1 /* restart */ );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2002-05-14 14:43:52 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_restart_gracefully ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2002-05-14 14:43:52 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e -> command = "core restart gracefully" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2008-02-08 21:26:32 +00:00
"Usage: core restart gracefully \n "
2007-10-11 19:03:06 +00:00
" Causes Asterisk to stop accepting new calls and exec() itself performing a cold \n "
" restart when all active calls have ended. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
if ( a -> argc != e -> args )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_NICE , 1 /* restart */ );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2002-05-14 14:43:52 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_restart_when_convenient ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2002-05-14 14:43:52 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e -> command = "core restart when convenient" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2008-02-08 21:26:32 +00:00
"Usage: core restart when convenient \n "
2007-10-11 19:03:06 +00:00
" Causes Asterisk to perform a cold restart when all active calls have ended. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
if ( a -> argc != e -> args )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
ast_cli ( a -> fd , "Waiting for inactivity to perform restart \n " );
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_REALLY_NICE , 1 /* restart */ );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2002-05-14 14:43:52 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_abort_shutdown ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2002-05-14 14:43:52 +00:00
{
2012-01-15 20:16:08 +00:00
int aborting_shutdown = 0 ;
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
2008-02-08 21:26:32 +00:00
e -> command = "core abort shutdown" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2008-02-08 21:26:32 +00:00
"Usage: core abort shutdown \n "
2007-10-11 19:03:06 +00:00
" Causes Asterisk to abort an executing shutdown or restart, and resume normal \n "
" call operations. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2008-02-08 21:26:32 +00:00
if ( a -> argc != e -> args )
2007-10-11 19:03:06 +00:00
return CLI_SHOWUSAGE ;
2012-01-15 20:16:08 +00:00
ast_mutex_lock ( & safe_system_lock );
if ( shuttingdown >= SHUTDOWN_FAST ) {
aborting_shutdown = 1 ;
shuttingdown = NOT_SHUTTING_DOWN ;
}
ast_mutex_unlock ( & safe_system_lock );
if ( aborting_shutdown ) {
ast_cancel_shutdown ();
}
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
1999-12-19 22:38:55 +00:00
}
2007-10-11 19:03:06 +00:00
static char * handle_bang ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2003-10-22 03:46:36 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "!" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2007-10-11 19:03:06 +00:00
"Usage: !<command> \n "
" Executes a given shell command \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
return CLI_SUCCESS ;
2003-10-22 03:46:36 +00:00
}
2007-02-13 05:57:52 +00:00
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 "
2005-12-23 03:04:38 +00:00
};
2007-10-11 19:03:06 +00:00
static char * show_warranty ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2005-12-23 03:04:38 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "core show warranty" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2007-10-11 19:03:06 +00:00
"Usage: core show warranty \n "
" Shows the warranty (if any) for this copy of Asterisk. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2005-12-23 03:04:38 +00:00
2008-11-02 18:52:13 +00:00
ast_cli ( a -> fd , "%s" , warranty_lines );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2005-12-23 03:04:38 +00:00
}
2007-02-13 05:57:52 +00:00
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 "
2005-12-23 03:04:38 +00:00
};
2007-10-11 19:03:06 +00:00
static char * show_license ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2005-12-23 03:04:38 +00:00
{
2007-10-11 19:03:06 +00:00
switch ( cmd ) {
case CLI_INIT :
e -> command = "core show license" ;
2012-03-22 19:51:16 +00:00
e -> usage =
2007-10-11 19:03:06 +00:00
"Usage: core show license \n "
" Shows the license(s) for this copy of Asterisk. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
2005-12-23 03:04:38 +00:00
2008-11-02 18:52:13 +00:00
ast_cli ( a -> fd , "%s" , license_lines );
2007-10-11 19:03:06 +00:00
return CLI_SUCCESS ;
2005-12-23 03:04:38 +00:00
}
2003-10-22 03:46:36 +00:00
1999-12-19 22:38:55 +00:00
#define ASTERISK_PROMPT "*CLI> "
2001-05-09 03:11:22 +00:00
#define ASTERISK_PROMPT2 "%s*CLI> "
2012-12-03 20:46:11 +00:00
/*!
* \brief Shutdown Asterisk CLI commands.
*
* \note These CLI commands cannot be unregistered at shutdown
* because one of them is likely the reason for the shutdown.
* The CLI generates a warning if a command is in-use when it is
* unregistered.
*/
static struct ast_cli_entry cli_asterisk_shutdown [] = {
2008-11-12 06:46:04 +00:00
AST_CLI_DEFINE ( handle_stop_now , "Shut down Asterisk immediately" ),
AST_CLI_DEFINE ( handle_stop_gracefully , "Gracefully shut down Asterisk" ),
AST_CLI_DEFINE ( handle_stop_when_convenient , "Shut down Asterisk at empty call volume" ),
2012-03-22 19:51:16 +00:00
AST_CLI_DEFINE ( handle_restart_now , "Restart Asterisk immediately" ),
2008-11-12 06:46:04 +00:00
AST_CLI_DEFINE ( handle_restart_gracefully , "Restart Asterisk gracefully" ),
AST_CLI_DEFINE ( handle_restart_when_convenient , "Restart Asterisk at empty call volume" ),
2012-12-03 20:46:11 +00:00
};
static struct ast_cli_entry cli_asterisk [] = {
AST_CLI_DEFINE ( handle_abort_shutdown , "Cancel a running shutdown" ),
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( show_warranty , "Show the warranty (if any) for this copy of Asterisk" ),
AST_CLI_DEFINE ( show_license , "Show the license(s) for this copy of Asterisk" ),
AST_CLI_DEFINE ( handle_version , "Display version info" ),
AST_CLI_DEFINE ( handle_bang , "Execute a shell command" ),
2006-09-18 19:54:18 +00:00
#if !defined(LOW_MEMORY)
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_show_version_files , "List versions of files used to build Asterisk" ),
AST_CLI_DEFINE ( handle_show_threads , "Show running threads" ),
2008-12-16 20:08:34 +00:00
#if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_show_sysinfo , "Show System Information" ),
2007-04-11 20:59:08 +00:00
#endif
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_show_profile , "Display profiling info" ),
AST_CLI_DEFINE ( handle_show_settings , "Show some core settings" ),
AST_CLI_DEFINE ( handle_clear_profile , "Clear profiling info" ),
2005-06-07 16:07:06 +00:00
#endif /* ! LOW_MEMORY */
2005-06-03 03:04:08 +00:00
};
2001-05-09 03:11:22 +00:00
2012-02-14 20:27:16 +00:00
struct el_read_char_state_struct {
unsigned int line_full : 1 ;
unsigned int prev_line_full : 1 ;
char prev_line_verbosity ;
};
static int el_read_char_state_init ( void * ptr )
{
struct el_read_char_state_struct * state = ptr ;
state -> line_full = 1 ;
state -> prev_line_full = 1 ;
state -> prev_line_verbosity = 0 ;
return 0 ;
}
AST_THREADSTORAGE_CUSTOM ( el_read_char_state , el_read_char_state_init , ast_free_ptr );
2008-08-10 19:35:50 +00:00
static int ast_el_read_char ( EditLine * editline , char * cp )
2003-02-06 06:15:25 +00:00
{
2006-03-31 00:33:28 +00:00
int num_read = 0 ;
int lastpos = 0 ;
2004-04-25 20:42:45 +00:00
struct pollfd fds [ 2 ];
2003-02-06 06:15:25 +00:00
int res ;
int max ;
2007-12-16 09:37:41 +00:00
#define EL_BUF_SIZE 512
char buf [ EL_BUF_SIZE ];
2012-02-14 20:27:16 +00:00
struct el_read_char_state_struct * state = ast_threadstorage_get ( & el_read_char_state , sizeof ( * state ));
2003-02-06 06:15:25 +00:00
for (;;) {
2004-04-25 20:42:45 +00:00
max = 1 ;
fds [ 0 ]. fd = ast_consock ;
fds [ 0 ]. events = POLLIN ;
2005-12-04 20:40:46 +00:00
if ( ! ast_opt_exec ) {
2004-04-25 20:42:45 +00:00
fds [ 1 ]. fd = STDIN_FILENO ;
fds [ 1 ]. events = POLLIN ;
max ++ ;
2003-06-23 16:40:12 +00:00
}
2009-03-18 02:28:55 +00:00
res = ast_poll ( fds , max , - 1 );
2003-02-06 06:15:25 +00:00
if ( res < 0 ) {
2011-07-18 12:54:29 +00:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler )
2008-12-12 22:04:26 +00:00
break ;
2003-02-06 06:15:25 +00:00
if ( errno == EINTR )
continue ;
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "poll failed: %s \n " , strerror ( errno ));
2003-02-06 06:15:25 +00:00
break ;
}
2005-12-04 20:40:46 +00:00
if ( ! ast_opt_exec && fds [ 1 ]. revents ) {
2003-02-06 06:15:25 +00:00
num_read = read ( STDIN_FILENO , cp , 1 );
if ( num_read < 1 ) {
break ;
2011-11-29 18:43:16 +00:00
} else {
2003-02-06 06:15:25 +00:00
return ( num_read );
2011-11-29 18:43:16 +00:00
}
2003-02-06 06:15:25 +00:00
}
2004-04-25 20:42:45 +00:00
if ( fds [ 0 ]. revents ) {
2012-02-14 20:27:16 +00:00
char level = 0 ;
char * curline = buf , * nextline ;
2003-02-06 06:15:25 +00:00
res = read ( ast_consock , buf , sizeof ( buf ) - 1 );
/* if the remote side disappears exit */
if ( res < 1 ) {
fprintf ( stderr , " \n Disconnected from Asterisk server \n " );
2005-12-04 20:40:46 +00:00
if ( ! ast_opt_reconnect ) {
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_FAST , 0 );
2004-06-25 14:39:38 +00:00
} else {
int tries ;
2004-06-25 21:14:03 +00:00
int reconnects_per_second = 20 ;
fprintf ( stderr , "Attempting to reconnect for 30 seconds \n " );
2008-02-11 18:27:47 +00:00
for ( tries = 0 ; tries < 30 * reconnects_per_second ; tries ++ ) {
2004-06-25 14:39:38 +00:00
if ( ast_tryconnect ()) {
2004-06-25 21:14:03 +00:00
fprintf ( stderr , "Reconnect succeeded after %.3f seconds \n " , 1.0 / reconnects_per_second * tries );
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2004-06-25 21:14:03 +00:00
WELCOME_MESSAGE ;
2007-10-15 13:07:48 +00:00
if ( ! ast_opt_mute )
2008-05-27 18:59:06 +00:00
fdsend ( ast_consock , "logger mute silent" );
2012-03-22 19:51:16 +00:00
else
2007-10-15 13:07:48 +00:00
printf ( "log and verbose output currently muted ('logger mute' to unmute) \n " );
2004-06-25 14:39:38 +00:00
break ;
2006-10-29 20:47:01 +00:00
} else
2004-06-25 14:39:38 +00:00
usleep ( 1000000 / reconnects_per_second );
}
2004-12-28 07:51:25 +00:00
if ( tries >= 30 * reconnects_per_second ) {
2004-06-25 14:39:38 +00:00
fprintf ( stderr , "Failed to reconnect for 30 seconds. Quitting. \n " );
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_FAST , 0 );
2004-06-25 14:39:38 +00:00
}
}
2012-04-17 21:08:05 +00:00
continue ;
2003-02-06 06:15:25 +00:00
}
buf [ res ] = '\0' ;
2008-05-05 23:00:31 +00:00
/* Write over the CLI prompt */
2008-11-02 18:52:13 +00:00
if ( ! ast_opt_exec && ! lastpos ) {
2010-06-01 15:18:59 +00:00
if ( write ( STDOUT_FILENO , " \r [0K", 5 ) < 0 ) {
2008-11-02 18:52:13 +00:00
}
}
2012-02-14 20:27:16 +00:00
do {
state -> prev_line_full = state -> line_full ;
if (( nextline = strchr ( curline , '\n' ))) {
state -> line_full = 1 ;
nextline ++ ;
} else {
state -> line_full = 0 ;
nextline = strchr ( curline , '\0' );
}
if ( state -> prev_line_full && VERBOSE_HASMAGIC ( curline )) {
level = VERBOSE_MAGIC2LEVEL ( curline );
curline ++ ;
2012-02-17 19:56:58 +00:00
} else if ( state -> prev_line_full && ! VERBOSE_HASMAGIC ( curline )) {
/* Non-verbose output */
level = 0 ;
2012-02-14 20:27:16 +00:00
} else {
level = state -> prev_line_verbosity ;
}
if (( ! state -> prev_line_full && state -> prev_line_verbosity <= option_verbose ) || ( state -> prev_line_full && level <= option_verbose )) {
if ( write ( STDOUT_FILENO , curline , nextline - curline ) < 0 ) {
}
}
state -> prev_line_verbosity = level ;
curline = nextline ;
} while ( ! ast_strlen_zero ( curline ));
2007-12-16 09:37:41 +00:00
if (( res < EL_BUF_SIZE - 1 ) && (( buf [ res - 1 ] == '\n' ) || ( buf [ res - 2 ] == '\n' ))) {
2003-03-06 06:00:17 +00:00
* cp = CC_REFRESH ;
return ( 1 );
2006-10-29 20:47:01 +00:00
} else
2003-02-06 06:15:25 +00:00
lastpos = 1 ;
}
}
* cp = '\0' ;
return ( 0 );
}
2008-07-30 15:30:18 +00:00
static struct ast_str * prompt = NULL ;
2008-08-10 19:35:50 +00:00
static char * cli_prompt ( EditLine * editline )
1999-12-19 22:38:55 +00:00
{
2008-07-30 15:30:18 +00:00
char tmp [ 100 ];
2004-03-26 04:59:41 +00:00
char * pfmt ;
2006-03-31 00:33:28 +00:00
int color_used = 0 ;
2008-07-30 15:30:18 +00:00
static int cli_prompt_changes = 0 ;
struct passwd * pw ;
struct group * gr ;
if ( prompt == NULL ) {
prompt = ast_str_create ( 100 );
} else if ( ! cli_prompt_changes ) {
2008-12-13 08:36:35 +00:00
return ast_str_buffer ( prompt );
2008-07-30 15:30:18 +00:00
} else {
ast_str_reset ( prompt );
}
2004-03-26 04:59:41 +00:00
if (( pfmt = getenv ( "ASTERISK_PROMPT" ))) {
2008-07-30 15:30:18 +00:00
char * t = pfmt ;
struct timeval ts = ast_tvnow ();
while ( * t != '\0' ) {
2004-03-26 04:59:41 +00:00
if ( * t == '%' ) {
2008-07-30 15:30:18 +00:00
char hostname [ MAXHOSTNAMELEN ] = "" ;
int i , which ;
2007-07-18 19:47:20 +00:00
struct ast_tm tm = { 0 , };
2004-05-02 19:13:16 +00:00
int fgcolor = COLOR_WHITE , bgcolor = COLOR_BLACK ;
2004-03-26 04:59:41 +00:00
t ++ ;
switch ( * t ) {
2006-03-31 00:33:28 +00:00
case 'C' : /* color */
t ++ ;
2009-08-10 19:20:57 +00:00
if ( sscanf ( t , "%30d;%30d%n" , & fgcolor , & bgcolor , & i ) == 2 ) {
2013-02-14 18:47:56 +00:00
ast_term_color_code ( & prompt , fgcolor , bgcolor );
2006-03-31 00:33:28 +00:00
t += i - 1 ;
2009-08-10 19:20:57 +00:00
} else if ( sscanf ( t , "%30d%n" , & fgcolor , & i ) == 1 ) {
2013-02-14 18:47:56 +00:00
ast_term_color_code ( & prompt , fgcolor , 0 );
2006-03-31 00:33:28 +00:00
t += i - 1 ;
}
2004-05-02 19:13:16 +00:00
2006-03-31 00:33:28 +00:00
/* If the color has been reset correctly, then there's no need to reset it later */
2006-10-29 20:47:01 +00:00
color_used = (( fgcolor == COLOR_WHITE ) && ( bgcolor == COLOR_BLACK )) ? 0 : 1 ;
2006-03-31 00:33:28 +00:00
break ;
case 'd' : /* date */
2008-07-30 15:30:18 +00:00
if ( ast_localtime ( & ts , & tm , NULL )) {
ast_strftime ( tmp , sizeof ( tmp ), "%Y-%m-%d" , & tm );
ast_str_append ( & prompt , 0 , "%s" , tmp );
cli_prompt_changes ++ ;
}
break ;
case 'g' : /* group */
if (( gr = getgrgid ( getgid ()))) {
ast_str_append ( & prompt , 0 , "%s" , gr -> gr_name );
}
2006-03-31 00:33:28 +00:00
break ;
case 'h' : /* hostname */
2008-07-30 15:30:18 +00:00
if ( ! gethostname ( hostname , sizeof ( hostname ) - 1 )) {
ast_str_append ( & prompt , 0 , "%s" , hostname );
} else {
ast_str_append ( & prompt , 0 , "%s" , "localhost" );
}
2006-03-31 00:33:28 +00:00
break ;
case 'H' : /* short hostname */
if ( ! gethostname ( hostname , sizeof ( hostname ) - 1 )) {
2008-07-30 15:30:18 +00:00
char * dotptr ;
if (( dotptr = strchr ( hostname , '.' ))) {
* dotptr = '\0' ;
2004-05-02 19:13:16 +00:00
}
2008-07-30 15:30:18 +00:00
ast_str_append ( & prompt , 0 , "%s" , hostname );
} else {
ast_str_append ( & prompt , 0 , "%s" , "localhost" );
}
2006-03-31 00:33:28 +00:00
break ;
2008-07-30 15:30:18 +00:00
#ifdef HAVE_GETLOADAVG
2006-03-31 00:33:28 +00:00
case 'l' : /* load avg */
t ++ ;
2009-08-10 19:20:57 +00:00
if ( sscanf ( t , "%30d" , & which ) == 1 && which > 0 && which <= 3 ) {
2008-07-30 15:30:18 +00:00
double list [ 3 ];
getloadavg ( list , 3 );
ast_str_append ( & prompt , 0 , "%.2f" , list [ which - 1 ]);
cli_prompt_changes ++ ;
2006-03-31 00:33:28 +00:00
}
break ;
2004-03-26 04:59:41 +00:00
#endif
2006-05-11 13:54:00 +00:00
case 's' : /* Asterisk system name (from asterisk.conf) */
2008-07-30 15:30:18 +00:00
ast_str_append ( & prompt , 0 , "%s" , ast_config_AST_SYSTEM_NAME );
2006-05-11 13:54:00 +00:00
break ;
2006-03-31 00:33:28 +00:00
case 't' : /* time */
2008-07-30 15:30:18 +00:00
if ( ast_localtime ( & ts , & tm , NULL )) {
ast_strftime ( tmp , sizeof ( tmp ), "%H:%M:%S" , & tm );
ast_str_append ( & prompt , 0 , "%s" , tmp );
cli_prompt_changes ++ ;
}
break ;
case 'u' : /* username */
if (( pw = getpwuid ( getuid ()))) {
ast_str_append ( & prompt , 0 , "%s" , pw -> pw_name );
}
2006-03-31 00:33:28 +00:00
break ;
case '#' : /* process console or remote? */
2008-07-30 15:30:18 +00:00
ast_str_append ( & prompt , 0 , "%c" , ast_opt_remote ? '>' : '#' );
2006-03-31 00:33:28 +00:00
break ;
case '%' : /* literal % */
2008-07-30 15:30:18 +00:00
ast_str_append ( & prompt , 0 , "%c" , '%' );
2006-03-31 00:33:28 +00:00
break ;
case '\0' : /* % is last character - prevent bug */
t -- ;
break ;
2004-03-26 04:59:41 +00:00
}
} else {
2008-12-13 08:36:35 +00:00
ast_str_append ( & prompt , 0 , "%c" , * t );
2004-03-26 04:59:41 +00:00
}
2009-01-03 20:29:54 +00:00
t ++ ;
2004-03-26 04:59:41 +00:00
}
2004-05-02 19:13:16 +00:00
if ( color_used ) {
/* Force colors back to normal at end */
2013-02-14 18:47:56 +00:00
ast_term_color_code ( & prompt , 0 , 0 );
2004-05-02 19:13:16 +00:00
}
2008-07-30 15:30:18 +00:00
} else if ( remotehostname ) {
ast_str_set ( & prompt , 0 , ASTERISK_PROMPT2 , remotehostname );
} else {
ast_str_set ( & prompt , 0 , "%s" , ASTERISK_PROMPT );
}
2003-02-06 06:15:25 +00:00
2012-03-22 19:51:16 +00:00
return ast_str_buffer ( prompt );
2003-02-06 06:15:25 +00:00
}
static char ** ast_el_strtoarr ( char * buf )
{
2007-12-12 17:15:56 +00:00
char ** match_list = NULL , ** match_list_tmp , * retstr ;
2004-06-29 04:42:19 +00:00
size_t match_list_len ;
2003-02-06 06:15:25 +00:00
int matches = 0 ;
2004-06-29 04:42:19 +00:00
match_list_len = 1 ;
2003-02-06 06:15:25 +00:00
while ( ( retstr = strsep ( & buf , " " )) != NULL ) {
2004-04-06 07:42:01 +00:00
if ( ! strcmp ( retstr , AST_CLI_COMPLETE_EOF ))
break ;
2004-06-29 04:42:19 +00:00
if ( matches + 1 >= match_list_len ) {
match_list_len <<= 1 ;
2007-12-12 17:15:56 +00:00
if (( match_list_tmp = ast_realloc ( match_list , match_list_len * sizeof ( char * )))) {
match_list = match_list_tmp ;
} else {
if ( match_list )
ast_free ( match_list );
return ( char ** ) NULL ;
2006-02-14 22:28:01 +00:00
}
2003-02-06 06:15:25 +00:00
}
2007-06-14 23:01:01 +00:00
match_list [ matches ++ ] = ast_strdup ( retstr );
2003-02-06 06:15:25 +00:00
}
2004-06-29 04:42:19 +00:00
if ( ! match_list )
return ( char ** ) NULL ;
2003-02-06 06:15:25 +00:00
2006-02-14 22:28:01 +00:00
if ( matches >= match_list_len ) {
2007-12-12 17:15:56 +00:00
if (( match_list_tmp = ast_realloc ( match_list , ( match_list_len + 1 ) * sizeof ( char * )))) {
match_list = match_list_tmp ;
} else {
if ( match_list )
ast_free ( match_list );
return ( char ** ) NULL ;
2006-02-14 22:28:01 +00:00
}
}
2003-02-06 06:15:25 +00:00
match_list [ matches ] = ( char * ) NULL ;
return match_list ;
}
static int ast_el_sort_compare ( const void * i1 , const void * i2 )
{
char * s1 , * s2 ;
s1 = (( char ** ) i1 )[ 0 ];
s2 = (( char ** ) i2 )[ 0 ];
return strcasecmp ( s1 , s2 );
}
static int ast_cli_display_match_list ( char ** matches , int len , int max )
{
int i , idx , limit , count ;
int screenwidth = 0 ;
int numoutput = 0 , numoutputline = 0 ;
screenwidth = ast_get_termcols ( STDOUT_FILENO );
/* find out how many entries can be put on one line, with two spaces between strings */
limit = screenwidth / ( max + 2 );
if ( limit == 0 )
limit = 1 ;
/* how many lines of output */
count = len / limit ;
if ( count * limit < len )
count ++ ;
idx = 1 ;
2006-01-07 15:17:10 +00:00
qsort ( & matches [ 0 ], ( size_t )( len ), sizeof ( char * ), ast_el_sort_compare );
2003-02-06 06:15:25 +00:00
for (; count > 0 ; count -- ) {
numoutputline = 0 ;
2008-02-11 18:27:47 +00:00
for ( i = 0 ; i < limit && matches [ idx ]; i ++ , idx ++ ) {
2003-02-06 06:15:25 +00:00
/* Don't print dupes */
if ( ( matches [ idx + 1 ] != NULL && strcmp ( matches [ idx ], matches [ idx + 1 ]) == 0 ) ) {
i -- ;
2007-06-06 21:20:11 +00:00
ast_free ( matches [ idx ]);
2004-07-16 20:41:17 +00:00
matches [ idx ] = NULL ;
2003-02-06 06:15:25 +00:00
continue ;
}
2004-10-01 18:35:35 +00:00
numoutput ++ ;
numoutputline ++ ;
2003-02-06 06:15:25 +00:00
fprintf ( stdout , "%-*s " , max , matches [ idx ]);
2007-06-06 21:20:11 +00:00
ast_free ( matches [ idx ]);
2004-07-16 20:41:17 +00:00
matches [ idx ] = NULL ;
2003-02-06 06:15:25 +00:00
}
if ( numoutputline > 0 )
fprintf ( stdout , " \n " );
}
return numoutput ;
1999-12-19 22:38:55 +00:00
}
2003-02-06 06:15:25 +00:00
2008-08-10 19:35:50 +00:00
static char * cli_complete ( EditLine * editline , int ch )
2001-05-09 03:11:22 +00:00
{
2006-03-31 00:33:28 +00:00
int len = 0 ;
2003-02-06 06:15:25 +00:00
char * ptr ;
int nummatches = 0 ;
char ** matches ;
int retval = CC_ERROR ;
2009-03-25 14:38:19 +00:00
char buf [ 2048 ], savechr ;
2001-05-09 03:11:22 +00:00
int res ;
2003-02-06 06:15:25 +00:00
2008-08-10 19:35:50 +00:00
LineInfo * lf = ( LineInfo * ) el_line ( editline );
2003-02-06 06:15:25 +00:00
2009-03-25 14:38:19 +00:00
savechr = * ( char * ) lf -> cursor ;
2003-09-04 03:55:41 +00:00
* ( char * ) lf -> cursor = '\0' ;
2003-02-21 06:00:08 +00:00
ptr = ( char * ) lf -> cursor ;
2003-02-06 06:15:25 +00:00
if ( ptr ) {
while ( ptr > lf -> buffer ) {
if ( isspace ( * ptr )) {
ptr ++ ;
break ;
}
ptr -- ;
}
}
len = lf -> cursor - ptr ;
2005-12-04 20:40:46 +00:00
if ( ast_opt_remote ) {
2012-03-22 19:51:16 +00:00
snprintf ( buf , sizeof ( buf ), "_COMMAND NUMMATCHES \" %s \" \" %s \" " , lf -> buffer , ptr );
2008-05-27 18:59:06 +00:00
fdsend ( ast_consock , buf );
2012-04-17 21:08:05 +00:00
if (( res = read ( ast_consock , buf , sizeof ( buf ) - 1 )) < 0 ) {
return ( char * )( CC_ERROR );
}
2003-02-06 06:15:25 +00:00
buf [ res ] = '\0' ;
nummatches = atoi ( buf );
if ( nummatches > 0 ) {
2004-04-06 07:42:01 +00:00
char * mbuf ;
int mlen = 0 , maxmbuf = 2048 ;
2012-03-22 19:51:16 +00:00
/* Start with a 2048 byte buffer */
2009-03-25 14:38:19 +00:00
if ( ! ( mbuf = ast_malloc ( maxmbuf ))) {
2012-07-25 12:21:54 +00:00
* (( char * ) lf -> cursor ) = savechr ;
2004-04-07 18:26:24 +00:00
return ( char * )( CC_ERROR );
2009-03-25 14:38:19 +00:00
}
2012-03-22 19:51:16 +00:00
snprintf ( buf , sizeof ( buf ), "_COMMAND MATCHESARRAY \" %s \" \" %s \" " , lf -> buffer , ptr );
2008-05-27 18:59:06 +00:00
fdsend ( ast_consock , buf );
2004-04-06 07:42:01 +00:00
res = 0 ;
2004-04-09 17:46:04 +00:00
mbuf [ 0 ] = '\0' ;
2004-04-06 07:42:01 +00:00
while ( ! strstr ( mbuf , AST_CLI_COMPLETE_EOF ) && res != - 1 ) {
if ( mlen + 1024 > maxmbuf ) {
/* Every step increment buffer 1024 bytes */
2012-03-22 19:51:16 +00:00
maxmbuf += 1024 ;
2009-03-25 14:38:19 +00:00
if ( ! ( mbuf = ast_realloc ( mbuf , maxmbuf ))) {
2012-07-25 12:21:54 +00:00
* (( char * ) lf -> cursor ) = savechr ;
2004-04-07 18:26:24 +00:00
return ( char * )( CC_ERROR );
2009-03-25 14:38:19 +00:00
}
2004-04-06 07:42:01 +00:00
}
/* Only read 1024 bytes at a time */
res = read ( ast_consock , mbuf + mlen , 1024 );
if ( res > 0 )
mlen += res ;
}
mbuf [ mlen ] = '\0' ;
2003-02-06 06:15:25 +00:00
2004-04-06 07:42:01 +00:00
matches = ast_el_strtoarr ( mbuf );
2007-06-06 21:20:11 +00:00
ast_free ( mbuf );
2003-02-06 06:15:25 +00:00
} else
matches = ( char ** ) NULL ;
2004-10-01 18:35:35 +00:00
} else {
2006-01-07 15:17:10 +00:00
char ** p , * oldbuf = NULL ;
nummatches = 0 ;
2003-02-06 06:15:25 +00:00
matches = ast_cli_completion_matches (( char * ) lf -> buffer , ptr );
2006-01-07 15:17:10 +00:00
for ( p = matches ; p && * p ; p ++ ) {
if ( ! oldbuf || strcmp ( * p , oldbuf ))
nummatches ++ ;
oldbuf = * p ;
}
2003-02-06 06:15:25 +00:00
}
if ( matches ) {
int i ;
int matches_num , maxlen , match_len ;
if ( matches [ 0 ][ 0 ] != '\0' ) {
2008-08-10 19:35:50 +00:00
el_deletestr ( editline , ( int ) len );
el_insertstr ( editline , matches [ 0 ]);
2003-02-06 06:15:25 +00:00
retval = CC_REFRESH ;
}
if ( nummatches == 1 ) {
/* Found an exact match */
2008-08-10 19:35:50 +00:00
el_insertstr ( editline , " " );
2003-02-06 06:15:25 +00:00
retval = CC_REFRESH ;
} else {
/* Must be more than one match */
2008-02-11 18:27:47 +00:00
for ( i = 1 , maxlen = 0 ; matches [ i ]; i ++ ) {
2003-02-06 06:15:25 +00:00
match_len = strlen ( matches [ i ]);
if ( match_len > maxlen )
maxlen = match_len ;
}
matches_num = i - 1 ;
if ( matches_num > 1 ) {
fprintf ( stdout , " \n " );
ast_cli_display_match_list ( matches , nummatches , maxlen );
retval = CC_REDISPLAY ;
2012-03-22 19:51:16 +00:00
} else {
2008-08-10 19:35:50 +00:00
el_insertstr ( editline , " " );
2003-02-06 06:15:25 +00:00
retval = CC_REFRESH ;
}
}
2007-01-19 17:02:36 +00:00
for ( i = 0 ; matches [ i ]; i ++ )
2007-06-06 21:20:11 +00:00
ast_free ( matches [ i ]);
ast_free ( matches );
2003-02-06 06:15:25 +00:00
}
2012-07-25 12:21:54 +00:00
* (( char * ) lf -> cursor ) = savechr ;
2009-03-25 14:38:19 +00:00
2004-06-13 21:25:10 +00:00
return ( char * )( long ) retval ;
2003-02-06 06:15:25 +00:00
}
static int ast_el_initialize ( void )
{
HistEvent ev ;
2011-05-05 21:20:00 +00:00
char * editor , * editrc = getenv ( "EDITRC" );
if ( ! ( editor = getenv ( "AST_EDITMODE" ))) {
if ( ! ( editor = getenv ( "AST_EDITOR" ))) {
editor = "emacs" ;
}
}
2003-02-06 06:15:25 +00:00
if ( el != NULL )
el_end ( el );
if ( el_hist != NULL )
history_end ( el_hist );
el = el_init ( "asterisk" , stdin , stdout , stderr );
el_set ( el , EL_PROMPT , cli_prompt );
2012-03-22 19:51:16 +00:00
el_set ( el , EL_EDITMODE , 1 );
2011-05-05 21:20:00 +00:00
el_set ( el , EL_EDITOR , editor );
2003-02-06 06:15:25 +00:00
el_hist = history_init ();
if ( ! el || ! el_hist )
return - 1 ;
/* setup history with 100 entries */
history ( el_hist , & ev , H_SETSIZE , 100 );
el_set ( el , EL_HIST , history , el_hist );
el_set ( el , EL_ADDFN , "ed-complete" , "Complete argument" , cli_complete );
/* Bind <tab> to command completion */
el_set ( el , EL_BIND , "^I" , "ed-complete" , NULL );
/* Bind ? to command completion */
el_set ( el , EL_BIND , "?" , "ed-complete" , NULL );
2004-03-29 04:12:13 +00:00
/* Bind ^D to redisplay */
el_set ( el , EL_BIND , "^D" , "ed-redisplay" , NULL );
2011-05-05 21:20:00 +00:00
/* Bind Delete to delete char left */
el_set ( el , EL_BIND , " \\ e[3~" , "ed-delete-next-char" , NULL );
/* Bind Home and End to move to line start and end */
el_set ( el , EL_BIND , " \\ e[1~" , "ed-move-to-beg" , NULL );
el_set ( el , EL_BIND , " \\ e[4~" , "ed-move-to-end" , NULL );
/* Bind C-left and C-right to move by word (not all terminals) */
el_set ( el , EL_BIND , " \\ eOC" , "vi-next-word" , NULL );
el_set ( el , EL_BIND , " \\ eOD" , "vi-prev-word" , NULL );
if ( editrc ) {
el_source ( el , editrc );
}
2003-02-06 06:15:25 +00:00
return 0 ;
}
2008-10-04 16:20:31 +00:00
#define MAX_HISTORY_COMMAND_LENGTH 256
2003-02-06 06:15:25 +00:00
static int ast_el_add_history ( char * buf )
{
HistEvent ev ;
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
2008-10-04 16:20:31 +00:00
if ( strlen ( buf ) > ( MAX_HISTORY_COMMAND_LENGTH - 1 ))
2004-01-23 19:12:44 +00:00
return 0 ;
2008-10-04 16:20:31 +00:00
return ( history ( el_hist , & ev , H_ENTER , ast_strip ( ast_strdupa ( buf ))));
2003-02-06 06:15:25 +00:00
}
static int ast_el_write_history ( char * filename )
{
HistEvent ev ;
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
return ( history ( el_hist , & ev , H_SAVE , filename ));
}
static int ast_el_read_history ( char * filename )
{
2012-07-25 12:21:54 +00:00
HistEvent ev ;
2003-02-06 06:15:25 +00:00
2012-07-25 12:21:54 +00:00
if ( el_hist == NULL || el == NULL ) {
2003-02-06 06:15:25 +00:00
ast_el_initialize ();
}
2012-07-25 12:21:54 +00:00
return history ( el_hist , & ev , H_LOAD , filename );
2001-05-09 03:11:22 +00:00
}
2008-11-02 18:52:13 +00:00
static void ast_remotecontrol ( char * data )
2001-05-09 03:11:22 +00:00
{
char buf [ 80 ];
int res ;
char filename [ 80 ] = "" ;
char * hostname ;
char * cpid ;
char * version ;
int pid ;
2006-03-31 00:33:28 +00:00
char * stringp = NULL ;
2003-02-06 06:15:25 +00:00
char * ebuf ;
int num = 0 ;
2008-12-11 23:38:56 +00:00
memset ( & sig_flags , 0 , sizeof ( sig_flags ));
signal ( SIGINT , __remote_quit_handler );
signal ( SIGTERM , __remote_quit_handler );
signal ( SIGHUP , __remote_quit_handler );
2008-11-02 18:52:13 +00:00
if ( read ( ast_consock , buf , sizeof ( buf )) < 0 ) {
ast_log ( LOG_ERROR , "read() failed: %s \n " , strerror ( errno ));
return ;
}
2008-07-08 20:17:08 +00:00
if ( data ) {
char prefix [] = "cli quit after " ;
2012-07-31 20:21:43 +00:00
char * tmp = ast_alloca ( strlen ( data ) + strlen ( prefix ) + 1 );
2008-07-08 20:17:08 +00:00
sprintf ( tmp , "%s%s" , prefix , data );
2008-11-02 18:52:13 +00:00
if ( write ( ast_consock , tmp , strlen ( tmp ) + 1 ) < 0 ) {
ast_log ( LOG_ERROR , "write() failed: %s \n " , strerror ( errno ));
2011-07-18 12:54:29 +00:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler ) {
2008-12-11 23:38:56 +00:00
return ;
}
2008-11-02 18:52:13 +00:00
}
2008-07-08 20:17:08 +00:00
}
2006-03-31 00:33:28 +00:00
stringp = buf ;
2003-02-06 06:15:25 +00:00
hostname = strsep ( & stringp , "/" );
cpid = strsep ( & stringp , "/" );
2003-09-05 04:36:58 +00:00
version = strsep ( & stringp , " \n " );
2001-05-09 03:11:22 +00:00
if ( ! version )
version = "<Version Unknown>" ;
2006-03-31 00:33:28 +00:00
stringp = hostname ;
2003-02-06 06:15:25 +00:00
strsep ( & stringp , "." );
2001-05-09 03:11:22 +00:00
if ( cpid )
pid = atoi ( cpid );
else
pid = - 1 ;
2007-10-13 05:53:19 +00:00
if ( ! data ) {
2012-02-14 20:27:16 +00:00
if ( ! ast_opt_mute ) {
2008-05-27 18:59:06 +00:00
fdsend ( ast_consock , "logger mute silent" );
2012-02-14 20:27:16 +00:00
} else {
2007-10-13 05:53:19 +00:00
printf ( "log and verbose output currently muted ('logger mute' to unmute) \n " );
2012-02-14 20:27:16 +00:00
}
2006-05-26 19:48:17 +00:00
}
2003-02-06 06:15:25 +00:00
2005-12-04 20:40:46 +00:00
if ( ast_opt_exec && data ) { /* hack to print output then exit if asterisk -rx is used */
2012-02-14 20:27:16 +00:00
int linefull = 1 , prev_linefull = 1 , prev_line_verbose = 0 ;
2006-06-13 03:56:09 +00:00
struct pollfd fds ;
fds . fd = ast_consock ;
fds . events = POLLIN ;
fds . revents = 0 ;
2012-02-14 20:27:16 +00:00
2010-03-18 18:18:43 +00:00
while ( ast_poll ( & fds , 1 , 60000 ) > 0 ) {
2008-08-10 19:35:50 +00:00
char buffer [ 512 ] = "" , * curline = buffer , * nextline ;
2008-05-05 23:00:31 +00:00
int not_written = 1 ;
2011-07-18 12:54:29 +00:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler ) {
2008-12-11 23:38:56 +00:00
break ;
}
2008-08-10 19:35:50 +00:00
if ( read ( ast_consock , buffer , sizeof ( buffer ) - 1 ) <= 0 ) {
2008-05-05 23:00:31 +00:00
break ;
}
do {
2012-02-14 20:27:16 +00:00
prev_linefull = linefull ;
2008-05-05 23:00:31 +00:00
if (( nextline = strchr ( curline , '\n' ))) {
2012-02-14 20:27:16 +00:00
linefull = 1 ;
2008-05-05 23:00:31 +00:00
nextline ++ ;
} else {
2012-02-14 20:27:16 +00:00
linefull = 0 ;
2008-05-05 23:00:31 +00:00
nextline = strchr ( curline , '\0' );
}
/* Skip verbose lines */
2012-02-14 20:27:16 +00:00
/* Prev line full? | Line is verbose | Last line verbose? | Print
* TRUE | TRUE* | TRUE | FALSE
* TRUE | TRUE* | FALSE | FALSE
* TRUE | FALSE* | TRUE | TRUE
* TRUE | FALSE* | FALSE | TRUE
* FALSE | TRUE | TRUE* | FALSE
* FALSE | TRUE | FALSE* | TRUE
* FALSE | FALSE | TRUE* | FALSE
* FALSE | FALSE | FALSE* | TRUE
*/
if (( ! prev_linefull && ! prev_line_verbose ) || ( prev_linefull && * curline > 0 )) {
prev_line_verbose = 0 ;
2008-05-05 23:00:31 +00:00
not_written = 0 ;
2008-11-02 18:52:13 +00:00
if ( write ( STDOUT_FILENO , curline , nextline - curline ) < 0 ) {
ast_log ( LOG_WARNING , "write() failed: %s \n " , strerror ( errno ));
}
2012-02-14 20:27:16 +00:00
} else {
prev_line_verbose = 1 ;
2008-05-05 23:00:31 +00:00
}
curline = nextline ;
} while ( ! ast_strlen_zero ( curline ));
2010-03-18 18:23:07 +00:00
/* No non-verbose output in 60 seconds. */
2008-05-05 23:00:31 +00:00
if ( not_written ) {
break ;
}
}
2003-06-23 16:40:12 +00:00
return ;
}
2008-11-05 22:19:18 +00:00
ast_verbose ( "Connected to Asterisk %s currently running on %s (pid = %d) \n " , version , hostname , pid );
remotehostname = hostname ;
2012-03-22 19:51:16 +00:00
if ( getenv ( "HOME" ))
2008-11-05 22:19:18 +00:00
snprintf ( filename , sizeof ( filename ), "%s/.asterisk_history" , getenv ( "HOME" ));
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
el_set ( el , EL_GETCFN , ast_el_read_char );
if ( ! ast_strlen_zero ( filename ))
ast_el_read_history ( filename );
2006-03-31 00:33:28 +00:00
for (;;) {
2003-02-06 06:15:25 +00:00
ebuf = ( char * ) el_gets ( el , & num );
2011-07-18 12:54:29 +00:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler ) {
2008-12-11 23:38:56 +00:00
break ;
}
2007-06-27 23:30:31 +00:00
if ( ! ebuf && write ( 1 , "" , 1 ) < 0 )
break ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( ebuf )) {
2003-02-06 06:15:25 +00:00
if ( ebuf [ strlen ( ebuf ) - 1 ] == '\n' )
ebuf [ strlen ( ebuf ) - 1 ] = '\0' ;
if ( ! remoteconsolehandler ( ebuf )) {
res = write ( ast_consock , ebuf , strlen ( ebuf ) + 1 );
2001-05-09 03:11:22 +00:00
if ( res < 1 ) {
ast_log ( LOG_WARNING , "Unable to write: %s \n " , strerror ( errno ));
break ;
}
}
}
}
printf ( " \n Disconnected from Asterisk server \n " );
}
2004-07-18 17:58:05 +00:00
static int show_version ( void )
{
2008-01-05 22:09:06 +00:00
printf ( "Asterisk %s \n " , ast_get_version ());
2004-07-18 17:58:05 +00:00
return 0 ;
}
2012-01-09 17:06:30 +00:00
static int show_cli_help ( void )
{
printf ( "Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others. \n " , ast_get_version ());
2002-09-12 03:22:07 +00:00
printf ( "Usage: asterisk [OPTIONS] \n " );
printf ( "Valid Options: \n " );
2004-07-18 17:58:05 +00:00
printf ( " -V Display version number and exit \n " );
2004-05-13 19:57:45 +00:00
printf ( " -C <configfile> Use an alternate configuration file \n " );
2004-07-18 16:20:54 +00:00
printf ( " -G <group> Run as a group other than the caller \n " );
printf ( " -U <user> Run as a user other than the caller \n " );
2004-05-13 19:57:45 +00:00
printf ( " -c Provide console CLI \n " );
printf ( " -d Enable extra debugging \n " );
2006-08-21 20:12:18 +00:00
#if HAVE_WORKING_FORK
2004-05-13 19:57:45 +00:00
printf ( " -f Do not fork \n " );
2006-08-21 20:12:18 +00:00
printf ( " -F Always fork \n " );
#endif
2004-05-13 19:57:45 +00:00
printf ( " -g Dump core in case of a crash \n " );
printf ( " -h This help screen \n " );
2004-12-28 07:51:25 +00:00
printf ( " -i Initialize crypto keys at startup \n " );
2008-06-12 17:27:55 +00:00
printf ( " -I Enable internal timing if DAHDI timer is available \n " );
2006-03-31 00:33:28 +00:00
printf ( " -L <load> Limit the maximum load average before rejecting new calls \n " );
printf ( " -M <value> Limit the maximum number of calls to the specified value \n " );
2007-09-12 15:19:11 +00:00
printf ( " -m Mute debugging and console output on the console \n " );
2004-05-13 19:57:45 +00:00
printf ( " -n Disable console colorization \n " );
printf ( " -p Run as pseudo-realtime thread \n " );
2004-12-28 07:51:25 +00:00
printf ( " -q Quiet mode (suppress output) \n " );
2004-05-13 19:57:45 +00:00
printf ( " -r Connect to Asterisk on this machine \n " );
2007-09-12 15:19:11 +00:00
printf ( " -R Same as -r, except attempt to reconnect if disconnected \n " );
2008-08-25 23:13:32 +00:00
printf ( " -s <socket> Connect to Asterisk via socket <socket> (only valid with -r) \n " );
2007-09-12 15:19:11 +00:00
printf ( " -t Record soundfiles in /var/tmp and move them where they \n " );
printf ( " belong after they are done \n " );
printf ( " -T Display the time in [Mmm dd hh:mm:ss] format for each line \n " );
printf ( " of output to the CLI \n " );
2004-05-13 19:57:45 +00:00
printf ( " -v Increase verbosity (multiple v's = more verbose) \n " );
2012-01-09 17:06:30 +00:00
printf ( " -x <cmd> Execute command <cmd> (implies -r) \n " );
2009-12-02 20:10:07 +00:00
printf ( " -X Execute includes by default (allows #exec in asterisk.conf) \n " );
2008-08-25 23:13:32 +00:00
printf ( " -W Adjust terminal colors to compensate for a light background \n " );
2002-09-12 03:22:07 +00:00
printf ( " \n " );
return 0 ;
}
2012-03-22 19:51:16 +00:00
static void ast_readconfig ( void )
2006-03-25 23:50:09 +00:00
{
2003-02-06 06:15:25 +00:00
struct ast_config * cfg ;
struct ast_variable * v ;
2007-12-18 09:26:03 +00:00
char * config = DEFAULT_CONFIG_FILE ;
2007-05-11 19:56:57 +00:00
char hostname [ MAXHOSTNAMELEN ] = "" ;
2010-07-20 19:35:02 +00:00
struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
2007-09-24 22:06:19 +00:00
struct {
unsigned int dbdir : 1 ;
unsigned int keydir : 1 ;
} found = { 0 , 0 };
2003-02-06 06:15:25 +00:00
2012-04-25 09:32:21 +00:00
/* Set default value */
option_dtmfminduration = AST_MIN_DTMF_DURATION ;
2005-12-04 20:40:46 +00:00
if ( ast_opt_override_config ) {
2008-03-26 18:39:06 +00:00
cfg = ast_config_load2 ( ast_config_AST_CONFIG_FILE , "" /* core, can't reload */ , config_flags );
2012-11-18 20:27:45 +00:00
if ( cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID ) {
fprintf ( stderr , "Unable to open specified master config file '%s', using built-in defaults \n " , ast_config_AST_CONFIG_FILE );
}
} else {
2008-03-26 18:39:06 +00:00
cfg = ast_config_load2 ( config , "" /* core, can't reload */ , config_flags );
2012-11-18 20:27:45 +00:00
}
2003-02-06 06:15:25 +00:00
/* init with buildtime config */
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . config_dir , DEFAULT_CONFIG_DIR , sizeof ( cfg_paths . config_dir ));
ast_copy_string ( cfg_paths . spool_dir , DEFAULT_SPOOL_DIR , sizeof ( cfg_paths . spool_dir ));
ast_copy_string ( cfg_paths . module_dir , DEFAULT_MODULE_DIR , sizeof ( cfg_paths . module_dir ));
2012-03-22 19:51:16 +00:00
snprintf ( cfg_paths . monitor_dir , sizeof ( cfg_paths . monitor_dir ), "%s/monitor" , cfg_paths . spool_dir );
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . var_dir , DEFAULT_VAR_DIR , sizeof ( cfg_paths . var_dir ));
ast_copy_string ( cfg_paths . data_dir , DEFAULT_DATA_DIR , sizeof ( cfg_paths . data_dir ));
ast_copy_string ( cfg_paths . log_dir , DEFAULT_LOG_DIR , sizeof ( cfg_paths . log_dir ));
ast_copy_string ( cfg_paths . agi_dir , DEFAULT_AGI_DIR , sizeof ( cfg_paths . agi_dir ));
ast_copy_string ( cfg_paths . db_path , DEFAULT_DB , sizeof ( cfg_paths . db_path ));
2011-12-07 20:15:29 +00:00
ast_copy_string ( cfg_paths . sbin_dir , DEFAULT_SBIN_DIR , sizeof ( cfg_paths . sbin_dir ));
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . key_dir , DEFAULT_KEY_DIR , sizeof ( cfg_paths . key_dir ));
ast_copy_string ( cfg_paths . pid_path , DEFAULT_PID , sizeof ( cfg_paths . pid_path ));
ast_copy_string ( cfg_paths . socket_path , DEFAULT_SOCKET , sizeof ( cfg_paths . socket_path ));
ast_copy_string ( cfg_paths . run_dir , DEFAULT_RUN_DIR , sizeof ( cfg_paths . run_dir ));
2005-07-25 23:09:13 +00:00
2009-03-27 14:00:18 +00:00
ast_set_default_eid ( & ast_eid_default );
2008-06-10 12:48:50 +00:00
2003-02-06 06:15:25 +00:00
/* no asterisk.conf? no problem, use buildtime config! */
2008-09-12 23:30:03 +00:00
if ( cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID ) {
2004-09-07 14:36:56 +00:00
return ;
2003-02-06 06:15:25 +00:00
}
2006-05-30 21:37:11 +00:00
for ( v = ast_variable_browse ( cfg , "files" ); v ; v = v -> next ) {
2006-10-29 20:47:01 +00:00
if ( ! strcasecmp ( v -> name , "astctlpermissions" ))
2007-12-20 09:55:05 +00:00
ast_copy_string ( ast_config_AST_CTL_PERMISSIONS , v -> value , sizeof ( ast_config_AST_CTL_PERMISSIONS ));
2006-10-29 20:47:01 +00:00
else if ( ! strcasecmp ( v -> name , "astctlowner" ))
2007-12-20 09:55:05 +00:00
ast_copy_string ( ast_config_AST_CTL_OWNER , v -> value , sizeof ( ast_config_AST_CTL_OWNER ));
2006-10-29 20:47:01 +00:00
else if ( ! strcasecmp ( v -> name , "astctlgroup" ))
2007-12-20 09:55:05 +00:00
ast_copy_string ( ast_config_AST_CTL_GROUP , v -> value , sizeof ( ast_config_AST_CTL_GROUP ));
2006-10-29 20:47:01 +00:00
else if ( ! strcasecmp ( v -> name , "astctl" ))
2007-12-20 09:55:05 +00:00
ast_copy_string ( ast_config_AST_CTL , v -> value , sizeof ( ast_config_AST_CTL ));
2005-02-11 21:16:34 +00:00
}
2006-05-30 21:37:11 +00:00
for ( v = ast_variable_browse ( cfg , "directories" ); v ; v = v -> next ) {
2003-02-06 06:15:25 +00:00
if ( ! strcasecmp ( v -> name , "astetcdir" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . config_dir , v -> value , sizeof ( cfg_paths . config_dir ));
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astspooldir" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . spool_dir , v -> value , sizeof ( cfg_paths . spool_dir ));
2008-03-04 23:10:45 +00:00
snprintf ( cfg_paths . monitor_dir , sizeof ( cfg_paths . monitor_dir ), "%s/monitor" , v -> value );
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astvarlibdir" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . var_dir , v -> value , sizeof ( cfg_paths . var_dir ));
2007-09-24 22:06:19 +00:00
if ( ! found . dbdir )
2007-12-20 09:55:05 +00:00
snprintf ( cfg_paths . db_path , sizeof ( cfg_paths . db_path ), "%s/astdb" , v -> value );
2007-09-24 22:06:19 +00:00
} else if ( ! strcasecmp ( v -> name , "astdbdir" )) {
2007-12-20 09:55:05 +00:00
snprintf ( cfg_paths . db_path , sizeof ( cfg_paths . db_path ), "%s/astdb" , v -> value );
2007-09-24 22:06:19 +00:00
found . dbdir = 1 ;
2006-04-15 22:53:53 +00:00
} else if ( ! strcasecmp ( v -> name , "astdatadir" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . data_dir , v -> value , sizeof ( cfg_paths . data_dir ));
2007-09-24 22:06:19 +00:00
if ( ! found . keydir )
2007-12-20 09:55:05 +00:00
snprintf ( cfg_paths . key_dir , sizeof ( cfg_paths . key_dir ), "%s/keys" , v -> value );
2007-09-24 22:06:19 +00:00
} else if ( ! strcasecmp ( v -> name , "astkeydir" )) {
2007-12-20 09:55:05 +00:00
snprintf ( cfg_paths . key_dir , sizeof ( cfg_paths . key_dir ), "%s/keys" , v -> value );
2007-09-24 22:06:19 +00:00
found . keydir = 1 ;
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astlogdir" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . log_dir , v -> value , sizeof ( cfg_paths . log_dir ));
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astagidir" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . agi_dir , v -> value , sizeof ( cfg_paths . agi_dir ));
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astrundir" )) {
2007-12-20 09:55:05 +00:00
snprintf ( cfg_paths . pid_path , sizeof ( cfg_paths . pid_path ), "%s/%s" , v -> value , "asterisk.pid" );
snprintf ( cfg_paths . socket_path , sizeof ( cfg_paths . socket_path ), "%s/%s" , v -> value , ast_config_AST_CTL );
ast_copy_string ( cfg_paths . run_dir , v -> value , sizeof ( cfg_paths . run_dir ));
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astmoddir" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . module_dir , v -> value , sizeof ( cfg_paths . module_dir ));
2011-12-07 20:15:29 +00:00
} else if ( ! strcasecmp ( v -> name , "astsbindir" )) {
ast_copy_string ( cfg_paths . sbin_dir , v -> value , sizeof ( cfg_paths . sbin_dir ));
2003-02-06 06:15:25 +00:00
}
}
2006-05-30 21:37:11 +00:00
for ( v = ast_variable_browse ( cfg , "options" ); v ; v = v -> next ) {
2005-02-09 00:13:52 +00:00
/* verbose level (-v at startup) */
2004-10-01 18:35:35 +00:00
if ( ! strcasecmp ( v -> name , "verbose" )) {
2005-07-25 23:09:13 +00:00
option_verbose = atoi ( v -> value );
2006-07-28 19:17:56 +00:00
/* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2005-03-11 07:24:10 +00:00
} else if ( ! strcasecmp ( v -> name , "timestamp" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_TIMESTAMP );
2005-02-09 00:13:52 +00:00
/* whether or not to support #exec in config files */
2005-02-02 03:38:24 +00:00
} else if ( ! strcasecmp ( v -> name , "execincludes" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_EXEC_INCLUDES );
2005-02-09 21:17:34 +00:00
/* debug level (-d at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "debug" )) {
2005-02-09 00:13:52 +00:00
option_debug = 0 ;
2009-08-10 19:20:57 +00:00
if ( sscanf ( v -> value , "%30d" , & option_debug ) != 1 ) {
2005-02-09 00:13:52 +00:00
option_debug = ast_true ( v -> value );
}
2006-08-21 20:12:18 +00:00
#if HAVE_WORKING_FORK
2005-02-09 00:13:52 +00:00
/* Disable forking (-f at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "nofork" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_NO_FORK );
2006-04-30 14:55:05 +00:00
/* Always fork, even if verbose or debug are enabled (-F at startup) */
} else if ( ! strcasecmp ( v -> name , "alwaysfork" )) {
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_ALWAYS_FORK );
2006-08-21 20:12:18 +00:00
#endif
2005-02-09 00:13:52 +00:00
/* Run quietly (-q at startup ) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "quiet" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_QUIET );
2005-02-09 00:13:52 +00:00
/* Run as console (-c at startup, implies nofork) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "console" )) {
2010-09-22 16:46:20 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE );
2006-01-16 17:37:44 +00:00
/* Run with high priority if the O/S permits (-p at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "highpriority" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_HIGH_PRIORITY );
2005-02-09 00:13:52 +00:00
/* Initialize RSA auth keys (IAX2) (-i at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "initcrypto" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_INIT_KEYS );
2005-02-09 00:13:52 +00:00
/* Disable ANSI colors for console (-c at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "nocolor" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_NO_COLOR );
2005-05-19 01:57:19 +00:00
/* Disable some usage warnings for picky people :p */
} else if ( ! strcasecmp ( v -> name , "dontwarn" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_DONT_WARN );
2005-02-09 00:13:52 +00:00
/* Dump core in case of crash (-g) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "dumpcore" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_DUMP_CORE );
2005-02-09 00:13:52 +00:00
/* Cache recorded sound files to another directory during recording */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "cache_record_files" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_CACHE_RECORD_FILES );
2005-02-09 00:13:52 +00:00
/* Specify cache directory */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "record_cache_dir" )) {
2005-07-25 23:09:13 +00:00
ast_copy_string ( record_cache_dir , v -> value , AST_CACHE_DIR_LEN );
2005-04-04 03:28:38 +00:00
/* Build transcode paths via SLINEAR, instead of directly */
} else if ( ! strcasecmp ( v -> name , "transcode_via_sln" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_TRANSCODE_VIA_SLIN );
2008-03-25 14:39:45 +00:00
/* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
} else if ( ! strcasecmp ( v -> name , "transmit_silence_during_record" ) || ! strcasecmp ( v -> name , "transmit_silence" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_TRANSMIT_SILENCE );
2006-03-30 06:07:04 +00:00
/* Enable internal timing */
} else if ( ! strcasecmp ( v -> name , "internal_timing" )) {
2006-03-30 06:26:16 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_INTERNAL_TIMING );
2012-04-25 09:32:21 +00:00
} else if ( ! strcasecmp ( v -> name , "mindtmfduration" )) {
if ( sscanf ( v -> value , "%30u" , & option_dtmfminduration ) != 1 ) {
option_dtmfminduration = AST_MIN_DTMF_DURATION ;
}
2005-05-18 01:49:13 +00:00
} else if ( ! strcasecmp ( v -> name , "maxcalls" )) {
2009-08-10 19:20:57 +00:00
if (( sscanf ( v -> value , "%30d" , & option_maxcalls ) != 1 ) || ( option_maxcalls < 0 )) {
2005-05-18 01:49:13 +00:00
option_maxcalls = 0 ;
}
2005-10-26 03:58:32 +00:00
} else if ( ! strcasecmp ( v -> name , "maxload" )) {
2005-10-31 21:25:21 +00:00
double test [ 1 ];
if ( getloadavg ( test , 1 ) == - 1 ) {
ast_log ( LOG_ERROR , "Cannot obtain load average on this system. 'maxload' option disabled. \n " );
option_maxload = 0.0 ;
2009-08-10 19:20:57 +00:00
} else if (( sscanf ( v -> value , "%30lf" , & option_maxload ) != 1 ) || ( option_maxload < 0.0 )) {
2005-10-26 03:58:32 +00:00
option_maxload = 0.0 ;
}
2006-11-22 17:41:07 +00:00
/* Set the maximum amount of open files */
} else if ( ! strcasecmp ( v -> name , "maxfiles" )) {
2007-02-14 20:22:20 +00:00
option_maxfiles = atoi ( v -> value );
set_ulimit ( option_maxfiles );
2005-11-08 00:30:29 +00:00
/* What user to run as */
} else if ( ! strcasecmp ( v -> name , "runuser" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . run_user , v -> value , sizeof ( cfg_paths . run_user ));
2005-11-08 00:30:29 +00:00
/* What group to run as */
} else if ( ! strcasecmp ( v -> name , "rungroup" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . run_group , v -> value , sizeof ( cfg_paths . run_group ));
2006-02-14 23:42:36 +00:00
} else if ( ! strcasecmp ( v -> name , "systemname" )) {
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . system_name , v -> value , sizeof ( cfg_paths . system_name ));
2007-05-11 19:56:57 +00:00
} else if ( ! strcasecmp ( v -> name , "autosystemname" )) {
if ( ast_true ( v -> value )) {
if ( ! gethostname ( hostname , sizeof ( hostname ) - 1 ))
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . system_name , hostname , sizeof ( cfg_paths . system_name ));
2007-05-11 19:56:57 +00:00
else {
2007-05-11 21:16:39 +00:00
if ( ast_strlen_zero ( ast_config_AST_SYSTEM_NAME )){
2007-12-20 09:55:05 +00:00
ast_copy_string ( cfg_paths . system_name , "localhost" , sizeof ( cfg_paths . system_name ));
2007-05-11 21:15:30 +00:00
}
ast_log ( LOG_ERROR , "Cannot obtain hostname for this system. Using '%s' instead. \n " , ast_config_AST_SYSTEM_NAME );
2007-05-11 19:56:57 +00:00
}
}
2006-05-30 21:37:11 +00:00
} else if ( ! strcasecmp ( v -> name , "languageprefix" )) {
ast_language_is_prefix = ast_true ( v -> value );
2011-09-13 21:40:56 +00:00
} else if ( ! strcasecmp ( v -> name , "defaultlanguage" )) {
ast_copy_string ( defaultlanguage , v -> value , MAX_LANGUAGE );
2012-03-22 19:51:16 +00:00
} else if ( ! strcasecmp ( v -> name , "lockmode" )) {
if ( ! strcasecmp ( v -> value , "lockfile" )) {
ast_set_lock_type ( AST_LOCK_TYPE_LOCKFILE );
} else if ( ! strcasecmp ( v -> value , "flock" )) {
ast_set_lock_type ( AST_LOCK_TYPE_FLOCK );
} else {
2007-08-28 16:28:26 +00:00
ast_log ( LOG_WARNING , "'%s' is not a valid setting for the lockmode option, "
"defaulting to 'lockfile' \n " , v -> value );
2012-03-22 19:51:16 +00:00
ast_set_lock_type ( AST_LOCK_TYPE_LOCKFILE );
2007-08-28 16:28:26 +00:00
}
2007-08-01 19:37:59 +00:00
#if defined(HAVE_SYSINFO)
2007-04-11 19:11:32 +00:00
} 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 */
2009-08-10 19:20:57 +00:00
if (( sscanf ( v -> value , "%30ld" , & option_minmemfree ) != 1 ) || ( option_minmemfree < 0 )) {
2007-04-11 19:11:32 +00:00
option_minmemfree = 0 ;
}
2007-04-11 20:59:08 +00:00
#endif
2008-06-10 12:48:50 +00:00
} else if ( ! strcasecmp ( v -> name , "entityid" )) {
struct ast_eid tmp_eid ;
if ( ! ast_str_to_eid ( & tmp_eid , v -> value )) {
ast_verbose ( "Successfully set global EID to '%s' \n " , v -> value );
2009-03-27 14:00:18 +00:00
ast_eid_default = tmp_eid ;
2008-06-10 12:48:50 +00:00
} else
ast_verbose ( "Invalid Entity ID '%s' provided \n " , v -> value );
2008-08-25 23:13:32 +00:00
} else if ( ! strcasecmp ( v -> name , "lightbackground" )) {
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_LIGHT_BACKGROUND );
2008-10-07 17:44:32 +00:00
} else if ( ! strcasecmp ( v -> name , "forceblackbackground" )) {
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND );
2009-01-13 23:00:27 +00:00
} else if ( ! strcasecmp ( v -> name , "hideconnect" )) {
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT );
2010-01-27 18:29:49 +00:00
} else if ( ! strcasecmp ( v -> name , "lockconfdir" )) {
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_LOCK_CONFIG_DIR );
2012-04-12 16:29:52 +00:00
} else if ( ! strcasecmp ( v -> name , "stdexten" )) {
/* Choose how to invoke the extensions.conf stdexten */
if ( ! strcasecmp ( v -> value , "gosub" )) {
ast_clear_flag ( & ast_options , AST_OPT_FLAG_STDEXTEN_MACRO );
} else if ( ! strcasecmp ( v -> value , "macro" )) {
ast_set_flag ( & ast_options , AST_OPT_FLAG_STDEXTEN_MACRO );
} else {
ast_log ( LOG_WARNING ,
"'%s' is not a valid setting for the stdexten option, defaulting to 'gosub' \n " ,
v -> value );
ast_clear_flag ( & ast_options , AST_OPT_FLAG_STDEXTEN_MACRO );
}
2004-09-07 01:49:08 +00:00
}
}
2008-06-03 22:05:16 +00:00
for ( v = ast_variable_browse ( cfg , "compat" ); v ; v = v -> next ) {
float version ;
2009-08-10 19:20:57 +00:00
if ( sscanf ( v -> value , "%30f" , & version ) != 1 ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Compatibility version for option '%s' is not a number: '%s' \n " , v -> name , v -> value );
2008-06-03 22:05:16 +00:00
continue ;
}
if ( ! strcasecmp ( v -> name , "app_set" )) {
ast_set2_flag ( & ast_compat , version < 1.5 ? 1 : 0 , AST_COMPAT_APP_SET );
} else if ( ! strcasecmp ( v -> name , "res_agi" )) {
ast_set2_flag ( & ast_compat , version < 1.5 ? 1 : 0 , AST_COMPAT_DELIM_RES_AGI );
} else if ( ! strcasecmp ( v -> name , "pbx_realtime" )) {
ast_set2_flag ( & ast_compat , version < 1.5 ? 1 : 0 , AST_COMPAT_DELIM_PBX_REALTIME );
}
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg );
2003-02-06 06:15:25 +00:00
}
2007-02-23 23:25:22 +00:00
static void * monitor_sig_flags ( void * unused )
{
for (;;) {
struct pollfd p = { sig_alert_pipe [ 0 ], POLLIN , 0 };
int a ;
2009-03-18 02:28:55 +00:00
ast_poll ( & p , 1 , - 1 );
2007-02-23 23:25:22 +00:00
if ( sig_flags . need_reload ) {
sig_flags . need_reload = 0 ;
ast_module_reload ( NULL );
}
if ( sig_flags . need_quit ) {
sig_flags . need_quit = 0 ;
2012-01-05 16:16:51 +00:00
if (( consolethread != AST_PTHREADT_NULL ) && ( consolethread != pthread_self ())) {
2011-07-18 12:54:29 +00:00
sig_flags . need_quit_handler = 1 ;
pthread_kill ( consolethread , SIGURG );
} else {
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_NORMAL , 0 );
2011-07-18 12:54:29 +00:00
}
2007-02-23 23:25:22 +00:00
}
2008-11-02 18:52:13 +00:00
if ( read ( sig_alert_pipe [ 0 ], & a , sizeof ( a )) != sizeof ( a )) {
}
2007-02-23 23:25:22 +00:00
}
return NULL ;
}
2007-12-18 23:06:05 +00:00
static void * canary_thread ( void * unused )
{
struct stat canary_stat ;
2008-08-10 19:35:50 +00:00
struct timeval now ;
2007-12-18 23:06:05 +00:00
/* Give the canary time to sing */
sleep ( 120 );
for (;;) {
2008-08-10 19:35:50 +00:00
now = ast_tvnow ();
2012-05-10 18:35:14 +00:00
if ( stat ( canary_filename , & canary_stat ) || now . tv_sec > canary_stat . st_mtime + 60 ) {
2012-01-09 17:06:30 +00:00
ast_log ( LOG_WARNING ,
"The canary is no more. He has ceased to be! "
"He's expired and gone to meet his maker! "
"He's a stiff! Bereft of life, he rests in peace. "
"His metabolic processes are now history! He's off the twig! "
"He's kicked the bucket. He's shuffled off his mortal coil, "
"run down the curtain, and joined the bleeding choir invisible!! "
"THIS is an EX-CANARY. (Reducing priority) \n " );
2007-12-18 23:06:05 +00:00
ast_set_priority ( 0 );
pthread_exit ( NULL );
}
/* Check the canary once a minute */
sleep ( 60 );
}
}
/* Used by libc's atexit(3) function */
static void canary_exit ( void )
{
if ( canary_pid > 0 )
kill ( canary_pid , SIGKILL );
}
2008-01-17 00:05:13 +00:00
static void run_startup_commands ( void )
{
int fd ;
2008-01-22 20:33:16 +00:00
struct ast_config * cfg ;
struct ast_flags cfg_flags = { 0 };
struct ast_variable * v ;
2008-01-17 00:05:13 +00:00
2008-03-26 18:39:06 +00:00
if ( ! ( cfg = ast_config_load2 ( "cli.conf" , "" /* core, can't reload */ , cfg_flags )))
2008-01-17 00:05:13 +00:00
return ;
2008-09-12 23:30:03 +00:00
if ( cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID ) {
return ;
}
2008-01-17 00:05:13 +00:00
2008-01-22 20:33:16 +00:00
fd = open ( "/dev/null" , O_RDWR );
2008-07-14 22:22:57 +00:00
if ( fd < 0 ) {
ast_config_destroy ( cfg );
2008-01-22 20:33:16 +00:00
return ;
2008-07-14 22:22:57 +00:00
}
2008-01-17 00:05:13 +00:00
2008-01-22 20:41:05 +00:00
for ( v = ast_variable_browse ( cfg , "startup_commands" ); v ; v = v -> next ) {
if ( ast_true ( v -> value ))
ast_cli_command ( fd , v -> name );
}
2008-01-17 00:05:13 +00:00
close ( fd );
2008-01-22 20:33:16 +00:00
ast_config_destroy ( cfg );
2008-01-17 00:05:13 +00:00
}
2010-05-28 22:50:06 +00:00
static void env_init ( void )
{
setenv ( "AST_SYSTEMNAME" , ast_config_AST_SYSTEM_NAME , 1 );
setenv ( "AST_BUILD_HOST" , ast_build_hostname , 1 );
setenv ( "AST_BUILD_DATE" , ast_build_date , 1 );
setenv ( "AST_BUILD_KERNEL" , ast_build_kernel , 1 );
setenv ( "AST_BUILD_MACHINE" , ast_build_machine , 1 );
setenv ( "AST_BUILD_OS" , ast_build_os , 1 );
setenv ( "AST_BUILD_USER" , ast_build_user , 1 );
setenv ( "AST_VERSION" , ast_get_version (), 1 );
}
2012-11-18 20:27:45 +00:00
static void print_intro_message ( const char * runuser , const char * rungroup )
{
2013-01-21 20:41:12 +00:00
if ( ast_opt_console || option_verbose || ( ast_opt_remote && ! ast_opt_exec )) {
2012-11-18 20:27:45 +00:00
if ( ast_register_verbose ( console_verboser )) {
fprintf ( stderr , "Unable to register console verboser? \n " );
return ;
}
WELCOME_MESSAGE ;
if ( runuser ) {
ast_verbose ( "Running as user '%s' \n " , runuser );
}
if ( rungroup ) {
ast_verbose ( "Running under group '%s' \n " , rungroup );
}
}
}
2012-12-03 20:46:11 +00:00
static void main_atexit ( void )
{
ast_cli_unregister_multiple ( cli_asterisk , ARRAY_LEN ( cli_asterisk ));
}
1999-11-15 04:57:28 +00:00
int main ( int argc , char * argv [])
{
2004-01-28 21:32:48 +00:00
int c ;
1999-12-19 22:38:55 +00:00
char filename [ 80 ] = "" ;
2006-03-31 00:33:28 +00:00
char hostname [ MAXHOSTNAMELEN ] = "" ;
2001-05-09 03:11:22 +00:00
char * xarg = NULL ;
2002-05-14 14:43:52 +00:00
int x ;
2002-09-12 03:22:07 +00:00
FILE * f ;
2001-05-09 03:11:22 +00:00
sigset_t sigs ;
2003-02-06 06:15:25 +00:00
int num ;
2010-06-28 21:50:57 +00:00
int isroot = 1 , rundir_exists = 0 ;
2003-02-06 06:15:25 +00:00
char * buf ;
2007-12-18 10:24:58 +00:00
const char * runuser = NULL , * rungroup = NULL ;
2007-12-19 07:01:40 +00:00
char * remotesock = NULL ;
2010-09-02 05:02:54 +00:00
int moduleresult ; /*!< Result from the module load subsystem */
struct rlimit l ;
2001-05-09 03:11:22 +00:00
2002-05-14 14:43:52 +00:00
/* Remember original args for restart */
2008-07-11 18:09:35 +00:00
if ( argc > ARRAY_LEN ( _argv ) - 1 ) {
fprintf ( stderr , "Truncating argument size to %d \n " , ( int ) ARRAY_LEN ( _argv ) - 1 );
argc = ARRAY_LEN ( _argv ) - 1 ;
2002-05-14 14:43:52 +00:00
}
2008-02-11 18:27:47 +00:00
for ( x = 0 ; x < argc ; x ++ )
2002-05-14 14:43:52 +00:00
_argv [ x ] = argv [ x ];
_argv [ x ] = NULL ;
2007-10-17 15:39:24 +00:00
if ( geteuid () != 0 )
isroot = 0 ;
2004-03-20 07:26:54 +00:00
/* if the progname is rasterisk consider it a remote console */
2004-10-01 18:35:35 +00:00
if ( argv [ 0 ] && ( strstr ( argv [ 0 ], "rasterisk" )) != NULL ) {
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE );
2004-03-20 07:26:54 +00:00
}
2005-05-08 16:44:25 +00:00
if ( gethostname ( hostname , sizeof ( hostname ) - 1 ))
2005-06-05 16:32:16 +00:00
ast_copy_string ( hostname , "<Unknown>" , sizeof ( hostname ));
2004-03-20 21:13:12 +00:00
ast_mainpid = getpid ();
2007-10-17 15:39:24 +00:00
2012-03-22 19:51:16 +00:00
if ( getenv ( "HOME" ))
1999-12-19 22:38:55 +00:00
snprintf ( filename , sizeof ( filename ), "%s/.asterisk_history" , getenv ( "HOME" ));
2012-09-21 17:14:59 +00:00
/*! \brief Check for options
*
* \todo Document these options
*/
2009-12-02 20:10:07 +00:00
while (( c = getopt ( argc , argv , "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:" )) != - 1 ) {
2009-11-26 02:09:58 +00:00
/*!\note Please keep the ordering here to alphabetical, capital letters
* first. This will make it easier in the future to select unused
* option flags for new features. */
2006-03-31 00:33:28 +00:00
switch ( c ) {
2009-11-26 02:09:58 +00:00
case 'B' : /* Force black background */
ast_set_flag ( & ast_options , AST_OPT_FLAG_FORCE_BLACK_BACKGROUND );
ast_clear_flag ( & ast_options , AST_OPT_FLAG_LIGHT_BACKGROUND );
break ;
2009-12-02 20:10:07 +00:00
case 'X' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_EXEC_INCLUDES );
break ;
2009-11-26 02:09:58 +00:00
case 'C' :
ast_copy_string ( cfg_paths . config_file , optarg , sizeof ( cfg_paths . config_file ));
ast_set_flag ( & ast_options , AST_OPT_FLAG_OVERRIDE_CONFIG );
break ;
case 'c' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE );
break ;
case 'd' :
option_debug ++ ;
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK );
break ;
2007-08-01 19:37:59 +00:00
#if defined(HAVE_SYSINFO)
2007-04-11 19:11:32 +00:00
case 'e' :
2009-08-10 19:20:57 +00:00
if (( sscanf ( & optarg [ 1 ], "%30ld" , & option_minmemfree ) != 1 ) || ( option_minmemfree < 0 )) {
2007-04-11 19:11:32 +00:00
option_minmemfree = 0 ;
}
break ;
2007-04-11 20:59:08 +00:00
#endif
2006-08-21 20:12:18 +00:00
#if HAVE_WORKING_FORK
2006-04-30 14:55:05 +00:00
case 'F' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_ALWAYS_FORK );
break ;
2006-08-21 20:12:18 +00:00
case 'f' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK );
break ;
#endif
2009-11-26 02:09:58 +00:00
case 'G' :
rungroup = ast_strdupa ( optarg );
2001-03-22 04:14:04 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'g' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_DUMP_CORE );
2002-05-14 14:43:52 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'h' :
show_cli_help ();
exit ( 0 );
case 'I' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_INTERNAL_TIMING );
2001-05-09 03:11:22 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'i' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_INIT_KEYS );
2004-06-25 14:39:38 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'L' :
if (( sscanf ( optarg , "%30lf" , & option_maxload ) != 1 ) || ( option_maxload < 0.0 )) {
option_maxload = 0.0 ;
}
1999-11-15 04:57:28 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'M' :
if (( sscanf ( optarg , "%30d" , & option_maxcalls ) != 1 ) || ( option_maxcalls < 0 )) {
option_maxcalls = 0 ;
}
1999-11-15 04:57:28 +00:00
break ;
2006-05-26 19:48:17 +00:00
case 'm' :
2006-05-26 21:47:52 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_MUTE );
2006-05-26 19:48:17 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'n' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_COLOR );
2005-05-18 01:49:13 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'p' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_HIGH_PRIORITY );
2005-10-26 03:58:32 +00:00
break ;
1999-11-15 04:57:28 +00:00
case 'q' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_QUIET );
1999-11-15 04:57:28 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'R' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT );
2005-03-11 07:24:10 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'r' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE );
2001-05-09 03:11:22 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 's' :
remotesock = ast_strdupa ( optarg );
2003-02-06 06:15:25 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'T' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_TIMESTAMP );
2006-03-30 06:07:04 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 't' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_CACHE_RECORD_FILES );
2001-12-25 21:12:07 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'U' :
runuser = ast_strdupa ( optarg );
2003-02-06 06:15:25 +00:00
break ;
2004-07-18 17:58:05 +00:00
case 'V' :
show_version ();
exit ( 0 );
2009-11-26 02:09:58 +00:00
case 'v' :
option_verbose ++ ;
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK );
2007-12-19 07:01:40 +00:00
break ;
2008-08-25 23:13:32 +00:00
case 'W' : /* White background */
ast_set_flag ( & ast_options , AST_OPT_FLAG_LIGHT_BACKGROUND );
2008-10-07 17:44:32 +00:00
ast_clear_flag ( & ast_options , AST_OPT_FLAG_FORCE_BLACK_BACKGROUND );
break ;
2009-11-26 02:09:58 +00:00
case 'x' :
2012-01-09 17:06:30 +00:00
/* -r is implied by -x so set the flags -r sets as well. */
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE );
2011-02-10 22:43:51 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_EXEC | AST_OPT_FLAG_NO_COLOR );
2009-11-26 02:09:58 +00:00
xarg = ast_strdupa ( optarg );
2008-08-25 23:13:32 +00:00
break ;
1999-11-15 04:57:28 +00:00
case '?' :
exit ( 1 );
}
}
2002-05-14 14:43:52 +00:00
2005-09-29 02:38:24 +00:00
/* For remote connections, change the name of the remote connection.
* We do this for the benefit of init scripts (which need to know if/when
* the main asterisk process has died yet). */
2005-12-04 20:40:46 +00:00
if ( ast_opt_remote ) {
2005-09-29 02:38:24 +00:00
strcpy ( argv [ 0 ], "rasterisk" );
for ( x = 1 ; x < argc ; x ++ ) {
argv [ x ] = argv [ 0 ] + 10 ;
}
}
2006-01-16 23:52:51 +00:00
ast_readconfig ();
2010-05-28 22:50:06 +00:00
env_init ();
2006-01-16 23:52:51 +00:00
2007-12-19 07:01:40 +00:00
if ( ast_opt_remote && remotesock != NULL )
2007-12-27 23:28:01 +00:00
ast_copy_string (( char * ) cfg_paths . socket_path , remotesock , sizeof ( cfg_paths . socket_path ));
2007-12-19 07:01:40 +00:00
2012-11-18 20:27:45 +00:00
if ( ! ast_language_is_prefix && ! ast_opt_remote ) {
fprintf ( stderr , "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 " );
}
2006-12-27 21:18:27 +00:00
2008-11-12 17:38:20 +00:00
if ( ast_opt_always_fork && ( ast_opt_remote || ast_opt_console )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "'alwaysfork' is not compatible with console or remote console mode; ignored \n " );
2008-11-12 17:38:20 +00:00
ast_clear_flag ( & ast_options , AST_OPT_FLAG_ALWAYS_FORK );
}
2005-12-04 20:40:46 +00:00
if ( ast_opt_dump_core ) {
2003-02-06 06:15:25 +00:00
memset ( & l , 0 , sizeof ( l ));
l . rlim_cur = RLIM_INFINITY ;
l . rlim_max = RLIM_INFINITY ;
if ( setrlimit ( RLIMIT_CORE , & l )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to disable core size resource limit: %s \n " , strerror ( errno ));
2003-02-06 06:15:25 +00:00
}
}
2010-09-02 05:02:54 +00:00
if ( getrlimit ( RLIMIT_NOFILE , & l )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to check file descriptor limit: %s \n " , strerror ( errno ));
2010-09-02 05:02:54 +00:00
}
#if !defined(CONFIGURE_RAN_AS_ROOT)
/* Check if select(2) will run with more file descriptors */
do {
int fd , fd2 ;
ast_fdset readers ;
struct timeval tv = { 0 , };
if ( l . rlim_cur <= FD_SETSIZE ) {
/* The limit of select()able FDs is irrelevant, because we'll never
* open one that high. */
break ;
}
if ( ! ( fd = open ( "/dev/null" , O_RDONLY ))) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Cannot open a file descriptor at boot? %s \n " , strerror ( errno ));
2010-09-02 05:02:54 +00:00
break ; /* XXX Should we exit() here? XXX */
}
2012-04-17 18:57:40 +00:00
fd2 = (( l . rlim_cur > sizeof ( readers ) * 8 ) ? sizeof ( readers ) * 8 : l . rlim_cur ) - 1 ;
2010-09-21 19:09:15 +00:00
if ( dup2 ( fd , fd2 ) < 0 ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Cannot open maximum file descriptor %d at boot? %s \n " , fd2 , strerror ( errno ));
2011-04-01 10:59:32 +00:00
close ( fd );
2010-09-02 05:02:54 +00:00
break ;
}
FD_ZERO ( & readers );
FD_SET ( fd2 , & readers );
if ( ast_select ( fd2 + 1 , & readers , NULL , NULL , & tv ) < 0 ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Maximum select()able file descriptor is %d \n " , FD_SETSIZE );
2010-09-02 05:02:54 +00:00
}
2011-04-01 10:59:32 +00:00
ast_FD_SETSIZE = l . rlim_cur > ast_FDMAX ? ast_FDMAX : l . rlim_cur ;
close ( fd );
close ( fd2 );
2010-09-02 05:02:54 +00:00
} while ( 0 );
#elif defined(HAVE_VARIABLE_FDSET)
2011-04-01 10:59:32 +00:00
ast_FD_SETSIZE = l . rlim_cur > ast_FDMAX ? ast_FDMAX : l . rlim_cur ;
2010-09-02 05:02:54 +00:00
#endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
2005-11-08 00:30:29 +00:00
if (( ! rungroup ) && ! ast_strlen_zero ( ast_config_AST_RUN_GROUP ))
rungroup = ast_config_AST_RUN_GROUP ;
if (( ! runuser ) && ! ast_strlen_zero ( ast_config_AST_RUN_USER ))
runuser = ast_config_AST_RUN_USER ;
2006-03-31 00:33:28 +00:00
2007-12-18 23:06:05 +00:00
/* Must install this signal handler up here to ensure that if the canary
* fails to execute that it doesn't kill the Asterisk process.
*/
2010-05-26 21:17:46 +00:00
sigaction ( SIGCHLD , & child_handler , NULL );
2007-12-18 23:06:05 +00:00
2010-02-25 21:22:39 +00:00
/* It's common on some platforms to clear /var/run at boot. Create the
* socket file directory before we drop privileges. */
2010-06-28 21:50:57 +00:00
if ( mkdir ( ast_config_AST_RUN_DIR , 0755 )) {
if ( errno == EEXIST ) {
rundir_exists = 1 ;
} else {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to create socket file directory. Remote consoles will not be able to connect! (%s) \n " , strerror ( x ));
2010-06-28 21:50:57 +00:00
}
2010-02-25 21:22:39 +00:00
}
2005-11-01 21:53:30 +00:00
#ifndef __CYGWIN__
2007-12-18 23:06:05 +00:00
if ( isroot ) {
2005-12-04 20:40:46 +00:00
ast_set_priority ( ast_opt_high_priority );
2007-12-18 23:06:05 +00:00
}
2005-03-26 07:16:18 +00:00
2007-10-17 15:39:24 +00:00
if ( isroot && rungroup ) {
2004-07-18 16:20:54 +00:00
struct group * gr ;
gr = getgrnam ( rungroup );
if ( ! gr ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "No such group '%s'! \n " , rungroup );
2004-07-18 16:20:54 +00:00
exit ( 1 );
}
2010-06-28 21:50:57 +00:00
if ( ! rundir_exists && chown ( ast_config_AST_RUN_DIR , - 1 , gr -> gr_gid )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to chgrp run directory to %d (%s) \n " , ( int ) gr -> gr_gid , rungroup );
2010-02-25 21:22:39 +00:00
}
2004-07-18 18:52:36 +00:00
if ( setgid ( gr -> gr_gid )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to setgid to %d (%s) \n " , ( int ) gr -> gr_gid , rungroup );
2004-07-18 16:20:54 +00:00
exit ( 1 );
}
2005-11-08 00:30:29 +00:00
if ( setgroups ( 0 , NULL )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to drop unneeded groups \n " );
2005-11-08 00:30:29 +00:00
exit ( 1 );
}
2004-07-18 16:20:54 +00:00
}
2007-10-17 15:39:24 +00:00
if ( runuser && ! ast_test_flag ( & ast_options , AST_OPT_FLAG_REMOTE )) {
2006-09-27 21:48:01 +00:00
#ifdef HAVE_CAP
int has_cap = 1 ;
#endif /* HAVE_CAP */
2004-07-18 16:20:54 +00:00
struct passwd * pw ;
pw = getpwnam ( runuser );
if ( ! pw ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "No such user '%s'! \n " , runuser );
2004-07-18 16:20:54 +00:00
exit ( 1 );
}
2010-02-25 21:22:39 +00:00
if ( chown ( ast_config_AST_RUN_DIR , pw -> pw_uid , - 1 )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to chown run directory to %d (%s) \n " , ( int ) pw -> pw_uid , runuser );
2010-02-25 21:22:39 +00:00
}
2006-09-27 21:48:01 +00:00
#ifdef HAVE_CAP
if ( prctl ( PR_SET_KEEPCAPS , 1 , 0 , 0 , 0 )) {
ast_log ( LOG_WARNING , "Unable to keep capabilities. \n " );
2006-10-02 16:00:11 +00:00
has_cap = 0 ;
2006-09-27 21:48:01 +00:00
}
#endif /* HAVE_CAP */
2007-10-17 15:39:24 +00:00
if ( ! isroot && pw -> pw_uid != geteuid ()) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Asterisk started as nonroot, but runuser '%s' requested. \n " , runuser );
2007-10-17 15:39:24 +00:00
exit ( 1 );
}
2006-01-08 20:27:22 +00:00
if ( ! rungroup ) {
if ( setgid ( pw -> pw_gid )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to setgid to %d! \n " , ( int ) pw -> pw_gid );
2006-01-08 20:27:22 +00:00
exit ( 1 );
}
2007-12-21 15:14:52 +00:00
if ( isroot && initgroups ( pw -> pw_name , pw -> pw_gid )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to init groups for '%s' \n " , runuser );
2006-01-07 20:08:51 +00:00
exit ( 1 );
}
2006-01-07 19:42:05 +00:00
}
2004-07-18 16:20:54 +00:00
if ( setuid ( pw -> pw_uid )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to setuid to %d (%s) \n " , ( int ) pw -> pw_uid , runuser );
2004-07-18 16:20:54 +00:00
exit ( 1 );
}
2006-09-27 21:48:01 +00:00
#ifdef HAVE_CAP
if ( has_cap ) {
2006-10-02 16:00:11 +00:00
cap_t cap ;
2009-01-29 23:15:40 +00:00
cap = cap_from_text ( "cap_net_admin=eip" );
2006-10-02 16:00:11 +00:00
2012-11-18 20:27:45 +00:00
if ( cap_set_proc ( cap )) {
fprintf ( stderr , "Unable to install capabilities. \n " );
}
if ( cap_free ( cap )) {
fprintf ( stderr , "Unable to drop capabilities. \n " );
}
2006-09-27 21:48:01 +00:00
}
#endif /* HAVE_CAP */
2004-07-18 16:20:54 +00:00
}
2005-11-01 21:53:30 +00:00
#endif /* __CYGWIN__ */
2006-02-14 18:47:16 +00:00
#ifdef linux
2006-02-14 02:41:42 +00:00
if ( geteuid () && ast_opt_dump_core ) {
if ( prctl ( PR_SET_DUMPABLE , 1 , 0 , 0 , 0 ) < 0 ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to set the process for core dumps after changing to a non-root user. %s \n " , strerror ( errno ));
2009-04-30 17:40:58 +00:00
}
2006-02-14 02:41:42 +00:00
}
2009-04-30 17:40:58 +00:00
#endif
2009-04-30 06:47:13 +00:00
{
2009-04-30 17:40:58 +00:00
#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
#if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
#define eaccess euidaccess
#endif
2009-04-30 06:47:13 +00:00
char dir [ PATH_MAX ];
if ( ! getcwd ( dir , sizeof ( dir )) || eaccess ( dir , R_OK | X_OK | F_OK )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to access the running directory (%s). Changing to '/' for compatibility. \n " , strerror ( errno ));
2009-04-30 06:47:13 +00:00
/* If we cannot access the CWD, then we couldn't dump core anyway,
* so chdir("/") won't break anything. */
if ( chdir ( "/" )) {
2009-04-30 17:40:58 +00:00
/* chdir(/) should never fail, so this ends up being a no-op */
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "chdir( \" / \" ) failed?!! %s \n " , strerror ( errno ));
2009-04-30 06:47:13 +00:00
}
2009-04-30 17:40:58 +00:00
} else
#endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
if ( ! ast_opt_no_fork && ! ast_opt_dump_core ) {
2009-04-30 06:47:13 +00:00
/* Backgrounding, but no cores, so chdir won't break anything. */
if ( chdir ( "/" )) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to chdir( \" / \" ) ?!! %s \n " , strerror ( errno ));
2009-04-30 06:47:13 +00:00
}
}
}
2006-02-14 02:41:42 +00:00
2001-05-09 03:11:22 +00:00
if ( ast_tryconnect ()) {
/* One is already running */
2005-12-04 20:40:46 +00:00
if ( ast_opt_remote ) {
2012-11-18 20:27:45 +00:00
multi_thread_safe = 1 ;
2005-12-04 20:40:46 +00:00
if ( ast_opt_exec ) {
2001-05-09 03:11:22 +00:00
ast_remotecontrol ( xarg );
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_FAST , 0 );
2001-05-09 03:11:22 +00:00
exit ( 0 );
}
2012-11-18 20:27:45 +00:00
print_intro_message ( runuser , rungroup );
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2001-05-09 03:11:22 +00:00
ast_remotecontrol ( NULL );
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_FAST , 0 );
2001-05-09 03:11:22 +00:00
exit ( 0 );
} else {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Asterisk already running on %s. Use 'asterisk -r' to connect. \n " , ast_config_AST_SOCKET );
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2001-05-09 03:11:22 +00:00
exit ( 1 );
}
2005-12-04 20:40:46 +00:00
} else if ( ast_opt_remote || ast_opt_exec ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Unable to connect to remote asterisk (does %s exist?) \n " , ast_config_AST_SOCKET );
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2001-05-09 03:11:22 +00:00
exit ( 1 );
}
2001-12-25 21:12:07 +00:00
2012-11-18 20:27:45 +00:00
/* This needs to remain as high up in the initial start up as possible.
* daemon causes a fork to occur, which has all sorts of unintended
* consequences for things that interact with threads. This call *must*
* occur before anything in Asterisk spawns or manipulates thread related
* primitives. */
2006-08-21 20:12:18 +00:00
#if HAVE_WORKING_FORK
2006-04-30 14:55:05 +00:00
if ( ast_opt_always_fork || ! ast_opt_no_fork ) {
2008-02-04 21:15:18 +00:00
#ifndef HAVE_SBIN_LAUNCHD
2008-11-02 18:52:13 +00:00
if ( daemon ( 1 , 0 ) < 0 ) {
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "daemon() failed: %s \n " , strerror ( errno ));
2013-01-19 00:19:19 +00:00
} else {
ast_mainpid = getpid ();
2008-11-02 18:52:13 +00:00
}
2008-02-04 21:15:18 +00:00
#else
2012-11-18 20:27:45 +00:00
fprintf ( stderr , "Mac OS X detected. Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'. \n " );
2008-02-04 21:15:18 +00:00
#endif
2001-05-09 03:11:22 +00:00
}
2006-08-21 20:12:18 +00:00
#endif
2001-12-25 21:12:07 +00:00
2012-11-18 20:27:45 +00:00
/* At this point everything has been forked successfully,
* we have determined that we aren't attempting to connect to
* an Asterisk instance, and that there isn't one already running. */
multi_thread_safe = 1 ;
2012-11-29 00:48:12 +00:00
#if defined(__AST_DEBUG_MALLOC)
__ast_mm_init_phase_1 ();
#endif /* defined(__AST_DEBUG_MALLOC) */
2009-05-18 19:17:15 +00:00
/* Spawning of astcanary must happen AFTER the call to daemon(3) */
if ( isroot && ast_opt_high_priority ) {
snprintf ( canary_filename , sizeof ( canary_filename ), "%s/alt.asterisk.canary.tweet.tweet.tweet" , ast_config_AST_RUN_DIR );
/* Don't let the canary child kill Asterisk, if it dies immediately */
2010-05-26 21:17:46 +00:00
sigaction ( SIGPIPE , & ignore_sig_handler , NULL );
2009-05-18 19:17:15 +00:00
canary_pid = fork ();
if ( canary_pid == 0 ) {
2011-12-07 20:15:29 +00:00
char canary_binary [ PATH_MAX ], ppid [ 12 ];
2009-05-18 19:17:15 +00:00
/* Reset signal handler */
signal ( SIGCHLD , SIG_DFL );
signal ( SIGPIPE , SIG_DFL );
ast_close_fds_above_n ( 0 );
ast_set_priority ( 0 );
2010-04-02 20:19:01 +00:00
snprintf ( ppid , sizeof ( ppid ), "%d" , ( int ) ast_mainpid );
2009-05-18 19:17:15 +00:00
2011-12-07 20:15:29 +00:00
/* Use the astcanary binary that we installed */
snprintf ( canary_binary , sizeof ( canary_binary ), "%s/astcanary" , ast_config_AST_SBIN_DIR );
execl ( canary_binary , "astcanary" , canary_filename , ppid , ( char * ) NULL );
2009-05-18 19:17:15 +00:00
/* Should never happen */
_exit ( 1 );
} else if ( canary_pid > 0 ) {
pthread_t dont_care ;
ast_pthread_create_detached ( & dont_care , NULL , canary_thread , NULL );
}
/* Kill the canary when we exit */
2010-01-15 21:40:14 +00:00
ast_register_atexit ( canary_exit );
2009-05-18 19:17:15 +00:00
}
2012-11-18 20:27:45 +00:00
/* Blindly write the PID file. */
unlink ( ast_config_AST_PID );
f = fopen ( ast_config_AST_PID , "w" );
if ( f ) {
2013-01-19 00:19:19 +00:00
fprintf ( f , "%ld \n " , ( long ) ast_mainpid );
2012-11-18 20:27:45 +00:00
fclose ( f );
} else {
fprintf ( stderr , "Unable to open pid file '%s': %s \n " , ast_config_AST_PID , strerror ( errno ));
}
/* Initialize the terminal. Since all processes have been forked,
* we can now start using the standard log messages.
*/
ast_term_init ();
printf ( "%s" , term_end ());
fflush ( stdout );
print_intro_message ( runuser , rungroup );
if ( ast_opt_console && ! option_verbose ) {
ast_verbose ( "[ Initializing Custom Configuration Options ] \n " );
}
/* custom config setup */
register_config_cli ();
read_config_maps ();
if ( ast_opt_console ) {
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
if ( ! ast_strlen_zero ( filename ))
ast_el_read_history ( filename );
}
2013-03-22 19:26:37 +00:00
ast_json_init ();
2012-11-18 20:27:45 +00:00
ast_ulaw_init ();
ast_alaw_init ();
tdd_init ();
callerid_init ();
ast_builtins_init ();
if ( ast_utils_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
if ( ast_tps_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
if ( ast_fd_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
if ( ast_pbx_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2009-03-25 21:57:19 +00:00
if ( ast_event_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2007-09-20 16:27:07 +00:00
2009-12-22 16:09:11 +00:00
#ifdef TEST_FRAMEWORK
if ( ast_test_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
#endif
2011-02-03 16:22:10 +00:00
if ( ast_translate_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2010-06-02 18:10:15 +00:00
ast_aoc_cli_init ();
2012-12-11 21:04:45 +00:00
ast_uuid_init ();
2010-06-02 18:10:15 +00:00
2013-01-25 14:01:04 +00:00
if ( ast_sorcery_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2013-03-08 15:15:13 +00:00
if ( stasis_init ()) {
printf ( "Stasis initialization failed. \n %s" , term_quit ());
exit ( 1 );
}
2001-05-09 03:11:22 +00:00
ast_makesocket ();
sigemptyset ( & sigs );
sigaddset ( & sigs , SIGHUP );
sigaddset ( & sigs , SIGTERM );
sigaddset ( & sigs , SIGINT );
sigaddset ( & sigs , SIGPIPE );
sigaddset ( & sigs , SIGWINCH );
pthread_sigmask ( SIG_BLOCK , & sigs , NULL );
2010-05-26 21:17:46 +00:00
sigaction ( SIGURG , & urg_handler , NULL );
2002-05-14 14:43:52 +00:00
signal ( SIGINT , __quit_handler );
signal ( SIGTERM , __quit_handler );
2010-05-26 21:17:46 +00:00
sigaction ( SIGHUP , & hup_handler , NULL );
sigaction ( SIGPIPE , & ignore_sig_handler , NULL );
2003-09-16 19:35:57 +00:00
2005-04-13 04:47:39 +00:00
/* ensure that the random number generators are seeded with a different value every time
Asterisk is started
*/
srand (( unsigned int ) getpid () + ( unsigned int ) time ( NULL ));
2006-01-10 00:55:45 +00:00
initstate (( unsigned int ) getpid () * 65536 + ( unsigned int ) time ( NULL ), randompool , sizeof ( randompool ));
2005-04-13 04:47:39 +00:00
2006-10-29 20:47:01 +00:00
if ( init_logger ()) { /* Start logging subsystem */
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
1999-11-15 04:57:28 +00:00
exit ( 1 );
2002-05-14 14:43:52 +00:00
}
2008-06-13 12:45:50 +00:00
2007-01-04 23:18:36 +00:00
threadstorage_init ();
2007-09-13 18:52:35 +00:00
astobj2_init ();
2011-02-03 16:22:10 +00:00
ast_format_attr_init ();
2011-02-22 23:04:49 +00:00
ast_format_list_init ();
ast_rtp_engine_init ();
2011-02-03 16:22:10 +00:00
2008-03-03 15:59:50 +00:00
ast_autoservice_init ();
2008-06-16 13:03:40 +00:00
if ( ast_timing_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2009-07-08 15:17:19 +00:00
if ( ast_ssl_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2008-11-01 21:10:07 +00:00
#ifdef AST_XML_DOCS
/* Load XML documentation. */
2008-11-10 13:53:23 +00:00
ast_xmldoc_load_documentation ();
2008-11-01 21:10:07 +00:00
#endif
2013-02-15 13:38:12 +00:00
aco_init ();
2013-04-16 15:33:59 +00:00
if ( devstate_init ()) {
printf ( "Device state core initialization failed. \n %s" , term_quit ());
exit ( 1 );
}
2013-03-16 15:45:58 +00:00
if ( app_init ()) {
printf ( "App core initialization failed. \n %s" , term_quit ());
exit ( 1 );
}
2011-07-06 20:58:12 +00:00
if ( astdb_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2011-06-01 21:31:40 +00:00
if ( ast_msg_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2010-04-22 18:07:02 +00:00
/* initialize the data retrieval API */
if ( ast_data_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2010-03-22 20:32:15 +00:00
ast_channels_init ();
2009-11-13 08:52:28 +00:00
if (( moduleresult = load_modules ( 1 ))) { /* Load modules, pre-load only */
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2009-11-13 08:52:28 +00:00
exit ( moduleresult == - 2 ? 2 : 1 );
2005-08-14 23:47:40 +00:00
}
2006-08-21 02:11:39 +00:00
2006-10-29 20:47:01 +00:00
if ( dnsmgr_init ()) { /* Initialize the DNS manager */
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2005-07-05 22:11:43 +00:00
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2012-07-11 18:33:36 +00:00
if ( ast_named_acl_init ()) { /* Initialize the Named ACL system */
printf ( "%s" , term_quit ());
exit ( 1 );
}
2006-10-29 20:47:01 +00:00
ast_http_init (); /* Start the HTTP server, if needed */
2006-08-21 02:11:39 +00:00
2009-06-04 14:31:24 +00:00
if ( init_manager ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2005-06-03 01:42:31 +00:00
if ( ast_cdr_engine_init ()) {
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2005-06-03 01:42:31 +00:00
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2009-06-26 15:28:53 +00:00
if ( ast_cel_engine_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2005-07-08 21:14:34 +00:00
if ( ast_device_state_engine_init ()) {
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2005-07-08 21:14:34 +00:00
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2012-06-04 20:26:12 +00:00
if ( ast_presence_state_engine_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2008-03-05 16:23:44 +00:00
ast_dsp_init ();
2006-01-12 17:14:58 +00:00
ast_udptl_init ();
2006-08-21 02:11:39 +00:00
2002-05-14 14:43:52 +00:00
if ( ast_image_init ()) {
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2001-10-11 18:51:39 +00:00
exit ( 1 );
2002-05-14 14:43:52 +00:00
}
2006-08-21 02:11:39 +00:00
2004-06-30 03:22:29 +00:00
if ( ast_file_init ()) {
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2004-06-30 03:22:29 +00:00
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2002-05-14 14:43:52 +00:00
if ( load_pbx ()) {
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
1999-11-15 04:57:28 +00:00
exit ( 1 );
2002-05-14 14:43:52 +00:00
}
2006-08-21 02:11:39 +00:00
2009-02-17 20:41:24 +00:00
if ( ast_indications_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2011-08-16 17:23:08 +00:00
if ( ast_features_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2008-01-23 23:09:11 +00:00
2003-05-01 04:29:25 +00:00
if ( ast_enum_init ()) {
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2003-05-01 04:29:25 +00:00
exit ( 1 );
}
2005-11-08 01:29:14 +00:00
2010-04-09 15:31:32 +00:00
if ( ast_cc_init ()) {
printf ( "%s" , term_quit ());
exit ( 1 );
}
2009-11-13 08:52:28 +00:00
if (( moduleresult = load_modules ( 0 ))) { /* Load modules */
2008-03-18 15:43:34 +00:00
printf ( "%s" , term_quit ());
2009-11-13 08:52:28 +00:00
exit ( moduleresult == - 2 ? 2 : 1 );
2006-08-21 22:23:26 +00:00
}
2008-12-01 18:52:14 +00:00
/* loads the cli_permissoins.conf file needed to implement cli restrictions. */
ast_cli_perms_init ( 0 );
2009-05-22 21:11:03 +00:00
ast_stun_init ();
2005-11-08 01:29:14 +00:00
dnsmgr_start_refresh ();
1999-11-15 04:57:28 +00:00
/* We might have the option of showing a console, but for now just
do nothing... */
2013-02-14 18:47:56 +00:00
ast_verb ( 0 , COLORIZE_FMT " \n " , COLORIZE ( COLOR_BRWHITE , COLOR_BLACK , "Asterisk Ready." ));
2012-02-14 20:27:16 +00:00
if ( ast_opt_no_fork ) {
2004-03-02 23:50:03 +00:00
consolethread = pthread_self ();
2012-02-14 20:27:16 +00:00
}
2006-08-21 02:11:39 +00:00
2012-02-14 20:27:16 +00:00
if ( pipe ( sig_alert_pipe )) {
2007-02-23 23:25:22 +00:00
sig_alert_pipe [ 0 ] = sig_alert_pipe [ 1 ] = - 1 ;
2012-02-14 20:27:16 +00:00
}
2007-02-23 23:25:22 +00:00
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_FULLY_BOOTED );
2012-07-10 22:26:27 +00:00
/*** DOCUMENTATION
<managerEventInstance>
<synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
</managerEventInstance>
***/
2010-05-24 22:21:58 +00:00
manager_event ( EVENT_FLAG_SYSTEM , "FullyBooted" , "Status: Fully Booted \r\n " );
2009-06-04 14:31:24 +00:00
ast_process_pending_reloads ();
2001-05-09 03:11:22 +00:00
pthread_sigmask ( SIG_UNBLOCK , & sigs , NULL );
2006-08-21 02:11:39 +00:00
2012-11-29 00:48:12 +00:00
#if defined(__AST_DEBUG_MALLOC)
2012-11-08 17:38:31 +00:00
__ast_mm_init_phase_2 ();
2012-11-29 00:48:12 +00:00
#endif /* defined(__AST_DEBUG_MALLOC) */
2006-08-21 02:11:39 +00:00
2007-11-27 21:10:50 +00:00
ast_lastreloadtime = ast_startuptime = ast_tvnow ();
2012-12-03 20:46:11 +00:00
ast_cli_register_multiple ( cli_asterisk_shutdown , ARRAY_LEN ( cli_asterisk_shutdown ));
2008-12-05 10:31:25 +00:00
ast_cli_register_multiple ( cli_asterisk , ARRAY_LEN ( cli_asterisk ));
2012-12-03 20:46:11 +00:00
ast_register_atexit ( main_atexit );
2006-08-21 02:11:39 +00:00
2008-01-17 00:05:13 +00:00
run_startup_commands ();
2005-12-04 20:40:46 +00:00
if ( ast_opt_console ) {
2000-01-02 20:59:00 +00:00
/* Console stuff now... */
/* Register our quit function */
2000-10-25 23:22:50 +00:00
char title [ 256 ];
2007-02-23 23:25:22 +00:00
2010-10-08 03:00:40 +00:00
ast_pthread_create_detached ( & mon_sig_flags , NULL , monitor_sig_flags , NULL );
2007-02-23 23:25:22 +00:00
2000-10-25 23:22:50 +00:00
set_icon ( "Asterisk" );
2006-05-08 12:32:44 +00:00
snprintf ( title , sizeof ( title ), "Asterisk Console on '%s' (pid %ld)" , hostname , ( long ) ast_mainpid );
2000-10-25 23:22:50 +00:00
set_title ( title );
2003-02-06 06:15:25 +00:00
2011-07-18 12:54:29 +00:00
el_set ( el , EL_GETCFN , ast_el_read_char );
2003-05-22 14:24:06 +00:00
for (;;) {
2011-07-18 12:54:29 +00:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler ) {
2012-01-15 20:16:08 +00:00
quit_handler ( 0 , SHUTDOWN_FAST , 0 );
2011-07-18 12:54:29 +00:00
break ;
}
2007-09-20 19:42:33 +00:00
buf = ( char * ) el_gets ( el , & num );
2007-06-27 20:47:45 +00:00
2007-06-27 23:30:31 +00:00
if ( ! buf && write ( 1 , "" , 1 ) < 0 )
goto lostterm ;
2007-06-24 20:07:15 +00:00
if ( buf ) {
if ( buf [ strlen ( buf ) - 1 ] == '\n' )
buf [ strlen ( buf ) - 1 ] = '\0' ;
2003-05-22 14:24:06 +00:00
2007-06-24 20:07:15 +00:00
consolehandler (( char * ) buf );
} else if ( ast_opt_remote && ( write ( STDOUT_FILENO , " \n Use EXIT or QUIT to exit the asterisk console \n " ,
2006-09-26 21:01:02 +00:00
strlen ( " \n Use 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 ;
2003-08-21 02:34:03 +00:00
}
2003-02-06 06:15:25 +00:00
}
2000-01-02 20:59:00 +00:00
}
2007-02-23 23:25:22 +00:00
monitor_sig_flags ( NULL );
2006-08-21 20:12:18 +00:00
2007-06-27 23:30:31 +00:00
lostterm :
1999-11-15 04:57:28 +00:00
return 0 ;
}