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
*
2018-03-27 15:27:09 +02:00
* Copyright (C) 1999 - 2018, 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-09-14 20:46:50 +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.
2013-07-05 17:33:33 +00:00
*
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
*
2021-03-03 14:44:22 -04:00
* Copyright (C) 1999 - 2021, Sangoma Technologies Corporation.
* Asterisk is a <a href="https://cdn.sangoma.com/wp-content/uploads/Sangoma-Trademark-Policy.pdf">registered trademark</a>
* of <a rel="nofollow" href="http://www.sangoma.com">Sangoma Technologies Corporation</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
2021-05-25 07:38:58 -03:00
* Use https://libera.chat IRC server to connect with Asterisk
2012-10-01 23:39:45 +00:00
* developers and users in realtime.
2013-07-05 17:33:33 +00:00
*
2012-10-01 23:39:45 +00:00
* \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"
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
#include <sys/vmmeter.h>
2018-04-20 12:50:03 +02:00
#if defined(__FreeBSD__) || defined(__DragonFly__)
2009-01-14 19:36:57 +00:00
#include <vm/vm_param.h>
#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"
2013-08-02 02:32:44 +00:00
#include "asterisk/pickup.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"
2005-04-21 06:02:45 +00:00
#include "asterisk/pbx.h"
#include "asterisk/app.h"
2019-04-09 13:48:49 -05:00
#include "asterisk/mwi.h"
2005-04-21 06:02:45 +00:00
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/io.h"
#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-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"
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-08-23 21:49:47 +00:00
#include "asterisk/bucket.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"
2013-05-08 13:39:08 +00:00
#include "asterisk/stasis_endpoints.h"
2013-07-08 14:42:57 +00:00
#include "asterisk/stasis_system.h"
2013-05-25 17:41:25 +00:00
#include "asterisk/security_events.h"
2013-10-04 16:01:48 +00:00
#include "asterisk/endpoints.h"
2014-07-20 22:06:33 +00:00
#include "asterisk/codec.h"
#include "asterisk/format_cache.h"
2015-01-29 14:38:23 +00:00
#include "asterisk/media_cache.h"
2016-07-23 07:51:48 -06:00
#include "asterisk/astdb.h"
2016-09-13 11:08:34 +02:00
#include "asterisk/options.h"
2020-07-13 16:06:14 -04:00
#include "asterisk/utf8.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
2013-05-24 20:44:07 +00:00
<managerEvent language="en_US" name="FullyBooted">
<managerEventInstance class="EVENT_FLAG_SYSTEM">
<synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
<syntax>
<parameter name="Status">
<para>Informational message</para>
</parameter>
2016-05-25 15:45:08 +02:00
<parameter name="Uptime">
<para>Seconds since start</para>
</parameter>
<parameter name="LastReload">
<para>Seconds since last reload</para>
</parameter>
2013-05-24 20:44:07 +00:00
</syntax>
</managerEventInstance>
</managerEvent>
<managerEvent language="en_US" name="Shutdown">
<managerEventInstance class="EVENT_FLAG_SYSTEM">
<synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
<syntax>
<parameter name="Shutdown">
<para>Whether the shutdown is proceeding cleanly (all channels
were hungup successfully) or uncleanly (channels will be
terminated)</para>
<enumlist>
<enum name="Uncleanly"/>
<enum name="Cleanly"/>
</enumlist>
</parameter>
<parameter name="Restart">
<para>Whether or not a restart will occur.</para>
<enumlist>
<enum name="True"/>
<enum name="False"/>
</enumlist>
</parameter>
</syntax>
</managerEventInstance>
</managerEvent>
2012-07-11 02:06:05 +00:00
***/
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
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 \
2021-03-03 14:44:22 -04:00
ast_verbose("Asterisk %s, Copyright (C) 1999 - 2021, Sangoma Technologies Corporation 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
2005-10-24 20:12:06 +00:00
static int ast_socket = - 1 ; /*!< UNIX Socket for allowing remote control */
2017-06-18 20:24:04 -04:00
static int ast_socket_is_sd = 0 ; /*!< Is socket activation responsible for ast_socket? */
2005-10-24 20:12:06 +00:00
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 */
2014-01-14 18:14:02 +00:00
/*! Verbosity level of this console. */
int option_verbose ;
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 );
2013-05-30 17:05:53 +00:00
int is_cleanup ;
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 ];
2015-11-25 20:29:55 +01:00
static int ast_el_add_history ( const char * );
static int ast_el_read_history ( const char * );
static int ast_el_write_history ( const char * );
static void ast_el_read_default_histfile ( void );
static void ast_el_write_default_histfile ( void );
static void asterisk_daemon ( int isroot , const char * runuser , const char * rungroup );
2003-02-06 06:15:25 +00:00
2004-02-23 03:43:21 +00:00
static char * _argv [ 256 ];
2015-02-11 17:39:13 +00:00
2012-01-15 20:16:08 +00:00
typedef enum {
2015-02-11 17:39:13 +00:00
/*! Normal operation */
NOT_SHUTTING_DOWN ,
/*! Committed to shutting down. Final phase */
SHUTTING_DOWN_FINAL ,
/*! Committed to shutting down. Initial phase */
SHUTTING_DOWN ,
/*!
* Valid values for quit_handler() niceness below.
* These shutdown/restart levels can be cancelled.
*
* Remote console exit right now
*/
2012-01-15 20:16:08 +00:00
SHUTDOWN_FAST ,
2015-02-11 17:39:13 +00:00
/*! core stop/restart now */
2012-01-15 20:16:08 +00:00
SHUTDOWN_NORMAL ,
2015-02-11 17:39:13 +00:00
/*! core stop/restart gracefully */
2012-01-15 20:16:08 +00:00
SHUTDOWN_NICE ,
2015-02-11 17:39:13 +00:00
/*! core stop/restart when convenient */
2012-01-15 20:16:08 +00:00
SHUTDOWN_REALLY_NICE
} shutdown_nice_t ;
2015-02-11 17:39:13 +00:00
2012-01-15 20:16:08 +00:00
static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN ;
2015-02-11 17:39:13 +00:00
/*! Prevent new channel allocation for shutdown. */
static int shutdown_pending ;
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 ];
2020-04-14 18:02:19 +02:00
#ifdef HAVE_CAP
static cap_t child_cap ;
#endif
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 ;
2018-11-11 08:34:53 -05:00
unsigned int need_el_end : 1 ;
2007-02-23 23:25:22 +00:00
} sig_flags ;
2007-01-30 17:23:56 +00:00
2016-09-19 05:46:27 -04:00
#if !defined(LOW_MEMORY)
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
}
}
2022-01-14 01:37:57 +00:00
/*! \brief Print the contents of a file */
static int print_file ( int fd , char * desc , const char * filename )
{
FILE * f ;
char c ;
if ( ! ( f = fopen ( filename , "r" ))) {
return - 1 ;
}
ast_cli ( fd , "%s" , desc );
while (( c = fgetc ( f )) != EOF ) {
ast_cli ( fd , "%c" , c );
}
fclose ( f );
/* no need for trailing new line, the file already has one */
return 0 ;
}
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 ];
2016-06-08 13:15:15 +02:00
struct rlimit limits ;
2016-07-23 07:51:48 -06:00
char pbx_uuid [ AST_UUID_STR_LEN ];
2022-01-14 01:37:57 +00:00
#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
char dir [ PATH_MAX ];
#endif
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 );
2016-07-23 07:51:48 -06:00
ast_pbx_uuid_get ( pbx_uuid , sizeof ( pbx_uuid ));
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 ());
2015-10-30 23:57:58 -04:00
ast_cli ( a -> fd , " Build Options: %s \n " , S_OR ( ast_get_build_opts (), "(none)" ));
2013-08-05 14:35:00 +00:00
if ( ast_option_maxcalls )
ast_cli ( a -> fd , " Maximum calls: %d (Current %d) \n " , ast_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 " );
2016-06-08 13:15:15 +02:00
if ( getrlimit ( RLIMIT_NOFILE , & limits )) {
ast_cli ( a -> fd , " Maximum open file handles: Error because of %s \n " , strerror ( errno ));
} else if ( limits . rlim_cur == RLIM_INFINITY ) {
ast_cli ( a -> fd , " Maximum open file handles: Unlimited \n " );
} else if ( limits . rlim_cur < ast_option_maxfiles ) {
ast_cli ( a -> fd , " Maximum open file handles: %d (is) %d (requested) \n " , ( int ) limits . rlim_cur , ast_option_maxfiles );
} else {
ast_cli ( a -> fd , " Maximum open file handles: %d \n " , ( int ) limits . rlim_cur );
}
2014-01-14 18:14:02 +00:00
ast_cli ( a -> fd , " Root console verbosity: %d \n " , option_verbose );
ast_cli ( a -> fd , " Current console verbosity: %d \n " , ast_verb_console_get ());
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " Debug level: %d \n " , option_debug );
2020-05-14 12:24:19 -06:00
ast_cli ( a -> fd , " Trace level: %d \n " , option_trace );
2022-01-14 01:37:57 +00:00
ast_cli ( a -> fd , " Dump core on crash: %s \n " , ast_opt_dump_core ? "Yes" : "No" );
print_file ( a -> fd , " Core dump file: " , "/proc/sys/kernel/core_pattern" );
2013-08-05 14:35:00 +00:00
ast_cli ( a -> fd , " Maximum load average: %lf \n " , ast_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 );
2016-07-23 07:51:48 -06:00
ast_cli ( a -> fd , " PBX UUID: %s \n " , pbx_uuid );
2013-08-05 14:35:00 +00:00
ast_cli ( a -> fd , " Default language: %s \n " , ast_defaultlanguage );
2007-10-11 19:03:06 +00:00
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 );
2022-01-14 01:37:57 +00:00
#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
#if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
#define eaccess euidaccess
#endif
if ( ! getcwd ( dir , sizeof ( dir ))) {
if ( eaccess ( dir , R_OK | X_OK | F_OK )) {
ast_cli ( a -> fd , " Running directory: %s \n " , "Unable to access" );
} else {
ast_cli ( a -> fd , " Running directory: %s (%s) \n " , dir , "Unable to access" );
}
} else {
ast_cli ( a -> fd , " Running directory: %s \n " , dir );
}
#endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
2007-10-11 19:03:06 +00:00
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" );
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" );
2018-03-16 09:19:11 -06:00
ast_cli ( a -> fd , " Generic PLC on equal codecs: %s \n " , ast_test_flag ( & ast_options , AST_OPT_FLAG_GENERIC_PLC_ON_EQUAL_CODECS ) ? "Enabled" : "Disabled" );
2020-02-03 09:24:58 -07:00
ast_cli ( a -> fd , " Hide Msg Chan AMI events: %s \n " , ast_opt_hide_messaging_ami_events ? "Enabled" : "Disabled" );
2012-04-25 09:32:21 +00:00
ast_cli ( a -> fd , " Min DTMF duration:: %u \n " , option_dtmfminduration );
2017-11-11 13:01:47 -06:00
#if !defined(LOW_MEMORY)
ast_cli ( a -> fd , " Cache media frames: %s \n " , ast_opt_cache_media_frames ? "Enabled" : "Disabled" );
#endif
2017-03-20 13:27:31 -05:00
ast_cli ( a -> fd , " RTP use dynamic payloads: %u \n " , ast_option_rtpusedynamic );
2007-02-14 20:22:20 +00:00
2016-09-13 11:08:34 +02:00
if ( ast_option_rtpptdynamic == AST_RTP_PT_LAST_REASSIGN ) {
ast_cli ( a -> fd , " RTP dynamic payload types: %u,%u-%u \n " ,
ast_option_rtpptdynamic ,
AST_RTP_PT_FIRST_DYNAMIC , AST_RTP_MAX_PT - 1 );
} else if ( ast_option_rtpptdynamic < AST_RTP_PT_LAST_REASSIGN ) {
ast_cli ( a -> fd , " RTP dynamic payload types: %u-%u,%u-%u \n " ,
ast_option_rtpptdynamic , AST_RTP_PT_LAST_REASSIGN ,
AST_RTP_PT_FIRST_DYNAMIC , AST_RTP_MAX_PT - 1 );
} else {
ast_cli ( a -> fd , " RTP dynamic payload types: %u-%u \n " ,
AST_RTP_PT_FIRST_DYNAMIC , AST_RTP_MAX_PT - 1 );
}
2007-10-11 19:03:06 +00:00
ast_cli ( a -> fd , " \n * Subsystems \n " );
ast_cli ( a -> fd , " ------------- \n " );
2020-12-18 10:16:38 -05:00
ast_cli ( a -> fd , " Manager (AMI): %s \n " , ast_manager_check_enabled () ? "Enabled" : "Disabled" );
ast_cli ( a -> fd , " Web Manager (AMI/HTTP): %s \n " , ast_webmanager_check_enabled () ? "Enabled" : "Disabled" );
2013-06-17 03:00:38 +00:00
ast_cli ( a -> fd , " Call data records: %s \n " , ast_cdr_is_enabled () ? "Enabled" : "Disabled" );
2007-10-11 19:03:06 +00:00
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 ;
}
#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 ;
2017-12-20 11:13:13 -05:00
#if defined(HAVE_SYSINFO) || defined(HAVE_SWAPCTL)
2018-01-27 16:44:21 +01:00
int totalswap = 0 ;
2010-05-28 20:53:04 +00:00
uint64_t freeswap = 0 ;
2017-12-20 11:13:13 -05:00
#endif
2010-05-24 18:19:08 +00:00
int nprocs = 0 ;
2008-12-16 20:08:34 +00:00
long uptime = 0 ;
#if defined(HAVE_SYSINFO)
2007-04-11 19:11:32 +00:00
struct sysinfo sys_info ;
2017-12-09 01:35:12 -05:00
#elif defined(HAVE_SYSCTL)
static int pageshift ;
struct vmtotal vmtotal ;
struct timeval boottime ;
time_t now ;
2018-01-27 16:44:21 +01:00
int mib [ 2 ], pagesize ;
#if defined(HAVE_SWAPCTL)
int usedswap = 0 ;
#endif
2017-12-09 01:35:12 -05:00
size_t len ;
#endif
switch ( cmd ) {
case CLI_INIT :
e -> command = "core show sysinfo" ;
e -> usage =
"Usage: core show sysinfo \n "
" List current system information. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
#if defined(HAVE_SYSINFO)
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)
/* 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 */
2018-01-27 16:44:21 +01:00
#if defined(HAVE_SWAPCTL)
2010-05-24 18:19:08 +00:00
swapmode ( & usedswap , & totalswap );
2008-12-16 20:08:34 +00:00
freeswap = ( totalswap - usedswap );
2018-01-27 16:44:21 +01:00
#endif
2008-12-16 20:08:34 +00:00
/* 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
ast_cli ( a -> fd , " \n System Statistics \n " );
ast_cli ( a -> fd , "----------------- \n " );
2014-05-09 22:49:26 +00:00
ast_cli ( a -> fd , " System Uptime: %ld hours \n " , uptime );
2010-05-24 18:19:08 +00:00
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
2017-12-20 11:13:13 -05:00
#if defined(HAVE_SYSINFO) || defined(HAVE_SWAPCTL)
2014-05-09 22:49:26 +00:00
ast_cli ( a -> fd , " Total Swap Space: %d 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 ;
2016-09-19 05:46:27 -04:00
#endif /* ! LOW_MEMORY */
2006-04-12 20:40:46 +00:00
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 )
{
2016-09-19 05:46:27 -04:00
#if !defined(LOW_MEMORY)
2006-04-12 20:40:46 +00:00
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 ;
2016-09-19 05:46:27 -04:00
#else /* if defined(LOW_MEMORY) */
return 0 ;
#endif
2006-04-12 20:40:46 +00:00
}
int64_t ast_profile ( int i , int64_t delta )
{
2016-09-19 05:46:27 -04:00
#if !defined(LOW_MEMORY)
2006-04-12 20:40:46 +00:00
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 ;
2016-09-19 05:46:27 -04:00
#else /* if defined(LOW_MEMORY) */
return 0 ;
#endif
2006-04-12 20:40:46 +00:00
}
2016-09-19 05:46:27 -04:00
#if !defined(LOW_MEMORY)
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. */
2021-11-11 05:24:38 +01:00
#if defined ( __i686__) && (defined(__FreeBSD__) || defined(__NetBSD__) || defined(linux))
2006-04-12 20:40:46 +00:00
#if defined(__FreeBSD__)
#include <machine/cpufunc.h>
2021-11-11 05:24:38 +01:00
#elif defined(__NetBSD__) || 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
2016-09-19 05:46:27 -04:00
#endif /* ! LOW_MEMORY */
2006-04-12 20:40:46 +00:00
int64_t ast_mark ( int i , int startstop )
{
2016-09-19 05:46:27 -04:00
#if !defined(LOW_MEMORY)
2006-04-12 20:40:46 +00:00
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 ;
2016-09-19 05:46:27 -04:00
#else /* if defined(LOW_MEMORY) */
return 0 ;
#endif
2006-04-12 20:40:46 +00:00
}
2016-09-19 05:46:27 -04:00
#if !defined(LOW_MEMORY)
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
2005-06-07 16:07:06 +00:00
#endif /* ! LOW_MEMORY */
2005-06-06 20:27:51 +00:00
2016-09-20 16:17:42 -04:00
int ast_pbx_uuid_get ( char * pbx_uuid , int length )
{
return ast_db_get ( "pbx" , "UUID" , pbx_uuid , length );
}
2013-05-24 20:44:07 +00:00
static void publish_fully_booted ( void )
{
2018-02-12 23:15:41 -05:00
struct ast_json * json_object ;
2016-05-25 15:45:08 +02:00
int uptime = 0 ;
int lastreloaded = 0 ;
struct timeval tmp ;
struct timeval curtime = ast_tvnow ();
2013-05-24 20:44:07 +00:00
2016-05-25 15:45:08 +02:00
if ( ast_startuptime . tv_sec ) {
tmp = ast_tvsub ( curtime , ast_startuptime );
uptime = ( int ) tmp . tv_sec ;
}
if ( ast_lastreloadtime . tv_sec ) {
tmp = ast_tvsub ( curtime , ast_lastreloadtime );
lastreloaded = ( int ) tmp . tv_sec ;
}
json_object = ast_json_pack ( "{s: s, s: i, s: i}" ,
"Status" , "Fully Booted" ,
"Uptime" , uptime ,
"LastReload" , lastreloaded );
2013-05-31 14:36:08 +00:00
ast_manager_publish_event ( "FullyBooted" , EVENT_FLAG_SYSTEM , json_object );
2018-02-12 23:15:41 -05:00
ast_json_unref ( json_object );
2013-05-24 20:44:07 +00:00
}
2013-05-30 17:05:53 +00:00
static void ast_run_atexits ( int run_cleanups )
2012-12-03 23:00:08 +00:00
{
struct ast_atexit * ae ;
AST_LIST_LOCK ( & atexits );
while (( ae = AST_LIST_REMOVE_HEAD ( & atexits , list ))) {
2013-05-30 17:05:53 +00:00
if ( ae -> func && ( ! ae -> is_cleanup || run_cleanups )) {
2012-12-03 23:00:08 +00:00
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 ;
}
2013-05-30 17:05:53 +00:00
static int register_atexit ( void ( * func )( void ), int is_cleanup )
2003-08-07 03:48:00 +00:00
{
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 ;
2013-05-30 17:05:53 +00:00
ae -> is_cleanup = is_cleanup ;
2007-09-08 18:45:51 +00:00
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
}
2013-05-30 17:05:53 +00:00
int ast_register_atexit ( void ( * func )( void ))
{
return register_atexit ( func , 0 );
}
int ast_register_cleanup ( void ( * func )( void ))
{
return register_atexit ( func , 1 );
}
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 );
}
2017-07-01 20:24:27 -04:00
/*! \brief fork and perform other preparations for spawning applications */
static pid_t safe_exec_prep ( int dualfork )
2006-05-25 18:31:19 +00:00
{
pid_t pid ;
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
2020-04-14 18:02:19 +02:00
cap_set_proc ( child_cap );
2009-01-29 23:15:40 +00:00
#endif
2006-10-18 21:05:52 +00:00
#ifdef HAVE_WORKING_FORK
2017-07-01 20:24:27 -04:00
if ( ast_opt_high_priority ) {
2006-05-01 21:48:30 +00:00
ast_set_priority ( 0 );
2017-07-01 20:24:27 -04:00
}
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
2017-07-01 20:24:27 -04:00
if ( dualfork ) {
#ifdef HAVE_WORKING_FORK
pid = fork ();
#else
pid = vfork ();
#endif
if ( pid < 0 ) {
/* Second fork failed. */
/* No logger available. */
_exit ( 1 );
}
if ( pid > 0 ) {
/* This is the first fork, exit so the reaper finishes right away. */
_exit ( 0 );
}
/* This is the second fork. The first fork will exit immediately so
* Asterisk doesn't have to wait for completion.
* ast_safe_system("cmd &") would run in the background, but the '&'
* cannot be added with ast_safe_execvp, so we have to double fork.
*/
}
}
if ( pid < 0 ) {
ast_log ( LOG_WARNING , "Fork failed: %s \n " , strerror ( errno ));
}
#else
ast_log ( LOG_WARNING , "Fork failed: %s \n " , strerror ( ENOTSUP ));
pid = - 1 ;
#endif
return pid ;
}
/*! \brief wait for spawned application to complete and unreplace sigchld */
static int safe_exec_wait ( pid_t pid )
{
int res = - 1 ;
#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
if ( pid > 0 ) {
2007-01-23 00:11:32 +00:00
for (;;) {
2017-07-01 20:24:27 -04:00
int status ;
2013-11-08 14:58:13 +00:00
res = waitpid ( pid , & status , 0 );
2004-03-21 18:15:37 +00:00
if ( res > - 1 ) {
2005-09-14 22:40:54 +00:00
res = WIFEXITED ( status ) ? WEXITSTATUS ( status ) : - 1 ;
break ;
2017-07-01 20:24:27 -04:00
}
if ( errno != EINTR ) {
2004-06-21 19:12:20 +00:00
break ;
2017-07-01 20:24:27 -04:00
}
2004-03-21 18:15:37 +00:00
}
}
2005-09-14 22:40:54 +00:00
2006-05-25 18:31:19 +00:00
ast_unreplace_sigchld ();
2006-08-21 20:12:18 +00:00
#endif
2005-09-14 22:40:54 +00:00
2004-03-21 18:15:37 +00:00
return res ;
}
2017-07-01 20:24:27 -04:00
int ast_safe_execvp ( int dualfork , const char * file , char * const argv [])
{
pid_t pid = safe_exec_prep ( dualfork );
if ( pid == 0 ) {
execvp ( file , argv );
_exit ( 1 );
/* noreturn from _exit */
}
return safe_exec_wait ( pid );
}
int ast_safe_system ( const char * s )
{
pid_t pid = safe_exec_prep ( 0 );
if ( pid == 0 ) {
execl ( "/bin/sh" , "/bin/sh" , "-c" , s , ( char * ) NULL );
_exit ( 1 );
/* noreturn from _exit */
}
return safe_exec_wait ( pid );
}
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 " );
}
/*!
2014-01-14 18:14:02 +00:00
* \brief log the string to all attached network console clients
2006-05-26 19:48:17 +00:00
*/
2016-05-14 07:24:07 -05:00
static void ast_network_puts_mutable ( const char * string , int level , int sublevel )
2006-05-26 19:48:17 +00:00
{
int x ;
2014-01-14 18:14:02 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; ++ x ) {
if ( consoles [ x ]. fd < 0
|| consoles [ x ]. mute
2016-05-14 07:24:07 -05:00
|| consoles [ x ]. levels [ level ]
|| ( level == __LOG_VERBOSE && consoles [ x ]. option_verbose < sublevel )) {
2006-05-26 21:47:52 +00:00
continue ;
2008-05-29 21:30:37 +00:00
}
2014-01-14 18:14:02 +00:00
fdprint ( consoles [ x ]. p [ 1 ], string );
2006-05-26 19:48:17 +00:00
}
}
/*!
2014-01-14 18:14:02 +00:00
* \brief log the string to the root console, and all attached
* network console clients
2006-05-26 19:48:17 +00:00
*/
2008-05-29 21:30:37 +00:00
void ast_console_puts_mutable ( const char * string , int level )
2016-05-14 07:24:07 -05:00
{
ast_console_puts_mutable_full ( string , level , 0 );
}
static int console_print ( const char * s );
void ast_console_puts_mutable_full ( const char * message , int level , int sublevel )
2006-05-26 19:48:17 +00:00
{
2014-01-14 18:14:02 +00:00
/* Send to the root console */
2016-05-14 07:24:07 -05:00
console_print ( message );
/* Wake up a poll()ing console */
if ( ast_opt_console && consolethread != AST_PTHREADT_NULL ) {
pthread_kill ( consolethread , SIGURG );
}
2014-01-14 18:14:02 +00:00
/* Send to any network console clients */
2016-05-14 07:24:07 -05:00
ast_network_puts_mutable ( message , level , sublevel );
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 )
2001-05-09 03:11:22 +00:00
{
2004-06-29 04:42:19 +00:00
int x ;
2014-01-14 18:14:02 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; ++ x ) {
if ( consoles [ x ]. fd < 0 ) {
continue ;
}
fdprint ( consoles [ x ]. p [ 1 ], string );
2004-06-29 04:42:19 +00:00
}
2004-01-12 05:05:35 +00:00
}
2005-10-24 20:12:06 +00:00
/*!
2014-01-14 18:14:02 +00:00
* \brief write the string to the root console, and all attached
* network console clients
2004-01-12 05:05:35 +00:00
*/
void ast_console_puts ( const char * string )
{
2014-01-14 18:14:02 +00:00
/* Send to the root console */
2004-06-29 04:42:19 +00:00
fputs ( string , stdout );
fflush ( stdout );
2014-01-14 18:14:02 +00:00
/* Send to any network console clients */
2004-06-29 04:42:19 +00:00
ast_network_puts ( string );
2004-01-12 05:05:35 +00:00
}
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 ;
}
2014-01-14 18:14:02 +00:00
/* This is the thread running the remote console on the main process. */
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 );
2014-01-14 18:14:02 +00:00
ast_verb_console_register ( & con -> option_verbose );
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 ;
}
}
2014-01-14 18:14:02 +00:00
ast_verb_console_unregister ();
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 ;
2017-12-18 21:12:47 -05:00
int poll_result ;
2004-04-25 20:42:45 +00:00
struct pollfd fds [ 1 ];
2017-12-18 21:12:47 -05:00
2006-03-31 00:33:28 +00:00
for (;;) {
2017-12-18 21:12:47 -05:00
if ( ast_socket < 0 ) {
2002-09-12 03:22:07 +00:00
return NULL ;
2017-12-18 21:12:47 -05:00
}
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 ;
2017-12-18 21:12:47 -05:00
poll_result = ast_poll ( fds , 1 , - 1 );
2006-07-03 05:14:06 +00:00
pthread_testcancel ();
2017-12-18 21:12:47 -05:00
if ( poll_result < 0 ) {
if ( errno != EINTR ) {
2004-04-25 20:42:45 +00:00
ast_log ( LOG_WARNING , "poll returned error: %s \n " , strerror ( errno ));
2017-12-18 21:12:47 -05:00
}
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 {
2015-02-21 02:51:35 +00:00
#if defined(SO_PASSCRED)
2008-12-01 18:52:14 +00:00
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 " );
2017-12-18 21:12:47 -05:00
close ( s );
2015-02-21 02:51:35 +00:00
} else
2008-12-01 18:52:14 +00:00
#endif
2015-02-21 02:51:35 +00:00
{
2008-12-01 18:52:14 +00:00
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 ));
fdprint ( s , "Server failed to create pipe \n " );
close ( s );
break ;
}
2017-12-07 10:52:39 -05:00
ast_fd_set_flags ( consoles [ x ]. p [ 1 ], O_NONBLOCK );
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 ;
2014-01-14 18:14:02 +00:00
/* Server default of remote console verbosity level is OFF. */
consoles [ x ]. option_verbose = 0 ;
consoles [ x ]. fd = s ;
2007-05-24 18:30:19 +00:00
if ( ast_pthread_create_detached_background ( & consoles [ x ]. t , NULL , netconsole , & consoles [ x ])) {
2014-01-14 18:14:02 +00:00
consoles [ x ]. fd = - 1 ;
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
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
2017-06-18 20:24:04 -04:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
2001-05-09 03:11:22 +00:00
consoles [ x ]. fd = - 1 ;
2017-06-18 20:24:04 -04:00
}
if ( ast_socket_is_sd ) {
ast_socket = ast_sd_get_fd_un ( SOCK_STREAM , ast_config_AST_SOCKET );
goto start_lthread ;
}
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
2017-06-18 20:24:04 -04:00
start_lthread :
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
2017-06-18 20:24:04 -04:00
if ( ast_socket_is_sd ) {
/* owner/group/permissions are set by systemd, we might not even have access
* to socket file so leave it alone */
return 0 ;
}
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 )) {
2014-05-09 22:49:26 +00:00
unsigned 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 ,
};
static void _hup_handler ( int num )
2001-05-09 03:11:22 +00:00
{
2017-11-09 20:47:27 -05:00
int save_errno = errno ;
2018-11-15 06:33:11 -05:00
if ( restartnow ) {
if ( el ) {
el_end ( el );
}
2004-02-23 03:43:21 +00:00
execvp ( _argv [ 0 ], _argv );
2018-11-15 06:33:11 -05:00
}
printf ( "Received HUP signal -- Reloading configs \n " );
2007-02-23 23:25:22 +00:00
sig_flags . need_reload = 1 ;
2017-11-09 20:47:27 -05:00
if ( ast_alertpipe_write ( sig_alert_pipe )) {
fprintf ( stderr , "hup_handler: write() failed: %s \n " , strerror ( errno ));
2008-11-02 18:52:13 +00:00
}
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
*/
2013-11-08 14:58:13 +00:00
for ( n = 0 ; waitpid ( - 1 , & status , WNOHANG ) > 0 ; n ++ )
2003-09-16 19:35:57 +00:00
;
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-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 );
}
2016-09-19 21:21:23 +02:00
/*! \brief Check whether we were set to high(er) priority. */
static int has_priority ( void )
{
/* Neither of these calls should fail with these arguments. */
#ifdef __linux__
/* For SCHED_OTHER, SCHED_BATCH and SCHED_IDLE, this will return
* 0. For the realtime priorities SCHED_RR and SCHED_FIFO, it
* will return something >= 1. */
return sched_getscheduler ( 0 );
#else
/* getpriority() can return a value in -20..19 (or even -INF..20)
* where negative numbers are high priority. We don't bother
* checking errno. If the query fails and it returns -1, we'll
* assume that we're running at high prio; a safe assumption
* that will enable the resource starvation monitor (canary)
* just in case. */
return ( getpriority ( PRIO_PROCESS , 0 ) < 0 );
#endif
}
2016-09-19 16:40:40 +02:00
/*! \brief Set priority on all known threads. */
static int set_priority_all ( int pri )
{
#if !defined(__linux__)
/* The non-linux version updates the entire process prio. */
return ast_set_priority ( pri );
#elif defined(LOW_MEMORY)
ast_log ( LOG_WARNING , "Unable to enumerate all threads to update priority \n " );
return ast_set_priority ( pri );
#else
struct thread_list_t * cur ;
struct sched_param sched ;
char const * policy_str ;
int policy ;
memset ( & sched , 0 , sizeof ( sched ));
if ( pri ) {
policy = SCHED_RR ;
policy_str = "realtime" ;
sched . sched_priority = 10 ;
} else {
policy = SCHED_OTHER ;
policy_str = "regular" ;
sched . sched_priority = 0 ;
}
if ( sched_setscheduler ( getpid (), policy , & sched )) {
ast_log ( LOG_WARNING , "Unable to set %s thread priority on main thread \n " , policy_str );
return - 1 ;
}
ast_verb ( 1 , "Setting %s thread priority on all threads \n " , policy_str );
AST_RWLIST_RDLOCK ( & thread_list );
AST_RWLIST_TRAVERSE ( & thread_list , cur , list ) {
/* Don't care about the return value. It should work. */
sched_setscheduler ( cur -> lwp , policy , & sched );
}
AST_RWLIST_UNLOCK ( & thread_list );
return 0 ;
#endif
}
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
return - 1 ;
2020-04-14 18:02:19 +02:00
}
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 ;
}
2015-02-11 17:39:13 +00:00
int ast_shutdown_final ( void )
{
return shuttingdown == SHUTTING_DOWN_FINAL ;
}
int ast_shutting_down ( void )
{
return shutdown_pending ;
}
int ast_cancel_shutdown ( void )
{
int shutdown_aborted = 0 ;
ast_mutex_lock ( & safe_system_lock );
if ( shuttingdown >= SHUTDOWN_FAST ) {
shuttingdown = NOT_SHUTTING_DOWN ;
shutdown_pending = 0 ;
shutdown_aborted = 1 ;
}
ast_mutex_unlock ( & safe_system_lock );
return shutdown_aborted ;
}
/*!
* \internal
* \brief Initiate system shutdown -- prevents new channels from being allocated.
*/
static void ast_begin_shutdown ( void )
{
ast_mutex_lock ( & safe_system_lock );
if ( shuttingdown != NOT_SHUTTING_DOWN ) {
shutdown_pending = 1 ;
}
ast_mutex_unlock ( & safe_system_lock );
}
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. */
2002-05-14 14:43:52 +00:00
}
2012-01-15 20:16:08 +00:00
/* It wasn't our time. */
}
2015-02-11 17:39:13 +00:00
#define SHUTDOWN_TIMEOUT 15 /* Seconds */
/*!
* \internal
* \brief Wait for all channels to die, a timeout, or shutdown cancelled.
* \since 13.3.0
*
* \param niceness Shutdown niceness in effect
* \param seconds Number of seconds to wait or less than zero if indefinitely.
*
* \retval zero if waiting wasn't necessary. We were idle.
* \retval non-zero if we had to wait.
*/
static int wait_for_channels_to_die ( shutdown_nice_t niceness , int seconds )
{
time_t start ;
time_t now ;
int waited = 0 ;
time ( & start );
for (;;) {
if ( ! ast_undestroyed_channels () || shuttingdown != niceness ) {
break ;
}
if ( seconds < 0 ) {
/* No timeout so just poll every second */
sleep ( 1 );
} else {
time ( & now );
/* Wait up to the given seconds for all channels to go away */
if ( seconds < ( now - start )) {
break ;
}
/* Sleep 1/10 of a second */
usleep ( 100000 );
}
waited = 1 ;
}
return waited ;
}
2012-01-15 20:16:08 +00:00
static int can_safely_quit ( shutdown_nice_t niceness , int restart )
{
2015-02-11 17:39:13 +00:00
int waited = 0 ;
2012-01-15 20:16:08 +00:00
/* 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. */
ast_cdr_engine_term ();
2012-10-02 01:47:16 +00:00
2015-02-11 17:39:13 +00:00
/*
* Shutdown the message queue for the technology agnostic message channel.
* This has to occur before we pause shutdown pending ast_undestroyed_channels.
*
* XXX This is not reversed on shutdown cancel.
*/
2012-09-11 21:17:53 +00:00
ast_msg_shutdown ();
2012-01-15 20:16:08 +00:00
if ( niceness == SHUTDOWN_NORMAL ) {
/* Begin shutdown routine, hanging up active channels */
2015-02-11 17:39:13 +00:00
ast_begin_shutdown ();
2013-08-29 22:49:24 +00:00
if ( ast_opt_console ) {
ast_verb ( 0 , "Beginning asterisk %s.... \n " , restart ? "restart" : "shutdown" );
2012-01-15 20:16:08 +00:00
}
2015-02-11 17:39:13 +00:00
ast_softhangup_all ();
waited |= wait_for_channels_to_die ( niceness , SHUTDOWN_TIMEOUT );
2012-01-15 20:16:08 +00:00
} else if ( niceness >= SHUTDOWN_NICE ) {
if ( niceness != SHUTDOWN_REALLY_NICE ) {
2015-02-11 17:39:13 +00:00
ast_begin_shutdown ();
2012-01-15 20:16:08 +00:00
}
2013-08-29 22:49:24 +00:00
if ( 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
}
2015-02-11 17:39:13 +00:00
waited |= wait_for_channels_to_die ( niceness , - 1 );
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 ) {
2013-08-29 22:49:24 +00:00
if ( shuttingdown == NOT_SHUTTING_DOWN && ast_opt_console ) {
2012-02-14 20:27:16 +00:00
ast_verb ( 0 , "Asterisk %s cancelled. \n " , restart ? "restart" : "shutdown" );
2012-01-15 20:16:08 +00:00
}
ast_mutex_unlock ( & safe_system_lock );
return 0 ;
}
2015-02-11 17:39:13 +00:00
if ( niceness >= SHUTDOWN_REALLY_NICE ) {
shuttingdown = SHUTTING_DOWN ;
ast_mutex_unlock ( & safe_system_lock );
/* No more Mr. Nice guy. We are committed to shutting down now. */
ast_begin_shutdown ();
ast_softhangup_all ();
waited |= wait_for_channels_to_die ( SHUTTING_DOWN , SHUTDOWN_TIMEOUT );
ast_mutex_lock ( & safe_system_lock );
}
shuttingdown = SHUTTING_DOWN_FINAL ;
2012-01-15 20:16:08 +00:00
ast_mutex_unlock ( & safe_system_lock );
2015-02-11 17:39:13 +00:00
if ( niceness >= SHUTDOWN_NORMAL && waited ) {
/*
* We were not idle. Give things in progress a chance to
* recognize the final shutdown phase.
*/
sleep ( 1 );
}
2012-01-15 20:16:08 +00:00
return 1 ;
}
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 ;
2013-08-29 21:37:29 +00:00
struct ast_json * json_object = NULL ;
2013-05-30 17:05:53 +00:00
int run_cleanups = niceness >= SHUTDOWN_NICE ;
2012-12-03 20:46:11 +00:00
2016-10-27 22:49:43 -04:00
if ( run_cleanups && modules_shutdown ()) {
ast_verb ( 0 , "Some modules could not be unloaded, switching to fast shutdown \n " );
run_cleanups = 0 ;
2012-01-15 20:16:08 +00:00
}
2016-06-27 21:26:54 +02:00
if ( ! restart ) {
ast_sd_notify ( "STOPPING=1" );
}
2008-11-05 22:19:18 +00:00
if ( ast_opt_console || ( ast_opt_remote && ! ast_opt_exec )) {
2015-11-25 20:29:55 +01:00
ast_el_write_default_histfile ();
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 );
}
2018-11-15 06:33:11 -05:00
} else if ( ! restart ) {
2018-11-11 08:34:53 -05:00
sig_flags . need_el_end = 1 ;
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 ();
2013-05-26 04:47:17 +00:00
/* Don't publish messages if we're a remote console - we won't have all of the Stasis
* topics or message types
*/
if ( ! ast_opt_remote ) {
json_object = ast_json_pack ( "{s: s, s: s}" ,
"Shutdown" , active_channels ? "Uncleanly" : "Cleanly" ,
"Restart" , restart ? "True" : "False" );
2013-05-31 14:36:08 +00:00
ast_manager_publish_event ( "Shutdown" , EVENT_FLAG_SYSTEM , json_object );
2013-08-29 21:37:29 +00:00
ast_json_unref ( json_object );
json_object = NULL ;
2013-05-26 04:47:17 +00:00
}
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 " );
2013-05-30 17:05:53 +00:00
ast_run_atexits ( run_cleanups );
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 ;
2017-06-18 20:24:04 -04:00
if ( ! ast_socket_is_sd ) {
unlink ( ast_config_AST_SOCKET );
}
2013-10-24 17:00:27 +00:00
pthread_kill ( lthread , SIGURG );
pthread_join ( lthread , NULL );
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 );
2017-11-09 20:47:27 -05:00
ast_alertpipe_close ( sig_alert_pipe );
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
sig_flags . need_quit = 1 ;
2017-11-09 20:47:27 -05:00
if ( ast_alertpipe_write ( sig_alert_pipe )) {
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 ;
}
2014-05-28 22:54:12 +00:00
static void set_header ( char * outbuf , int maxout , char level )
2002-05-14 14:43:52 +00:00
{
2013-08-29 22:49:24 +00:00
const char * cmp ;
2014-05-28 22:54:12 +00:00
char date [ 40 ];
2013-08-29 22:49:24 +00:00
switch ( level ) {
2014-05-28 22:54:12 +00:00
case 0 : cmp = NULL ;
break ;
2013-08-29 22:49:24 +00:00
case 1 : cmp = VERBOSE_PREFIX_1 ;
break ;
case 2 : cmp = VERBOSE_PREFIX_2 ;
break ;
case 3 : cmp = VERBOSE_PREFIX_3 ;
break ;
default : cmp = VERBOSE_PREFIX_4 ;
break ;
}
2008-05-05 23:00:31 +00:00
2014-05-28 22:54:12 +00:00
if ( ast_opt_timestamp ) {
struct ast_tm tm ;
struct timeval now = ast_tvnow ();
ast_localtime ( & now , & tm , NULL );
ast_strftime ( date , sizeof ( date ), ast_logger_get_dateformat (), & tm );
2002-05-14 14:43:52 +00:00
}
2013-08-29 22:49:24 +00:00
2014-05-28 22:54:12 +00:00
snprintf ( outbuf , maxout , "%s%s%s%s%s%s" ,
ast_opt_timestamp ? "[" : "" ,
ast_opt_timestamp ? date : "" ,
ast_opt_timestamp ? "] " : "" ,
cmp ? ast_term_color ( COLOR_GRAY , 0 ) : "" ,
cmp ? cmp : "" ,
cmp ? ast_term_reset () : "" );
2002-05-14 14:43:52 +00:00
}
2013-08-29 22:49:24 +00:00
struct console_state_data {
char verbose_line_level ;
};
static int console_state_init ( void * ptr )
{
struct console_state_data * state = ptr ;
state -> verbose_line_level = 0 ;
return 0 ;
}
AST_THREADSTORAGE_CUSTOM ( console_state , console_state_init , ast_free_ptr );
2016-05-14 07:24:07 -05:00
static int console_print ( const char * s )
2013-08-29 22:49:24 +00:00
{
struct console_state_data * state =
ast_threadstorage_get ( & console_state , sizeof ( * state ));
char prefix [ 80 ];
2013-09-17 18:44:11 +00:00
const char * c ;
2013-08-30 15:39:09 +00:00
int num , res = 0 ;
2013-09-17 18:44:11 +00:00
unsigned int newline ;
2013-08-29 22:49:24 +00:00
do {
if ( VERBOSE_HASMAGIC ( s )) {
2014-05-28 22:54:12 +00:00
2013-09-17 18:44:11 +00:00
/* always use the given line's level, otherwise
we'll use the last line's level */
2013-08-29 22:49:24 +00:00
state -> verbose_line_level = VERBOSE_MAGIC2LEVEL ( s );
2014-05-28 22:54:12 +00:00
2013-08-29 22:49:24 +00:00
/* move past magic */
s ++ ;
2014-05-28 22:54:12 +00:00
set_header ( prefix , sizeof ( prefix ), state -> verbose_line_level );
2013-09-17 18:44:11 +00:00
} else {
2013-08-29 22:49:24 +00:00
* prefix = '\0' ;
}
2013-09-17 18:44:11 +00:00
c = s ;
2013-08-29 22:49:24 +00:00
2013-09-17 18:44:11 +00:00
/* for a given line separate on verbose magic, newline, and eol */
if (( s = strchr ( c , '\n' ))) {
2013-08-29 22:49:24 +00:00
++ s ;
2013-09-17 18:44:11 +00:00
newline = 1 ;
} else {
s = strchr ( c , '\0' );
newline = 0 ;
2013-08-29 22:49:24 +00:00
}
/* check if we should write this line after calculating begin/end
so we process the case of a higher level line embedded within
two lower level lines */
if ( state -> verbose_line_level > option_verbose ) {
continue ;
}
2014-05-28 22:54:12 +00:00
if ( ! ast_strlen_zero ( prefix )) {
2013-08-29 22:49:24 +00:00
fputs ( prefix , stdout );
}
2013-08-30 15:39:09 +00:00
num = s - c ;
if ( fwrite ( c , sizeof ( char ), num , stdout ) < num ) {
break ;
}
2013-08-29 22:49:24 +00:00
if ( ! res ) {
/* if at least some info has been written
we'll want to return true */
res = 1 ;
}
} while ( * s );
2013-09-17 18:44:11 +00:00
if ( newline ) {
/* if ending on a newline then reset last level to zero
since what follows may be not be logging output */
state -> verbose_line_level = 0 ;
}
2013-08-29 22:49:24 +00:00
if ( res ) {
fflush ( stdout );
}
return res ;
}
2015-11-25 20:29:55 +01:00
static int ast_all_zeros ( const char * s )
2004-08-01 18:12:52 +00:00
{
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 ;
}
2014-01-14 18:14:02 +00:00
/* This is the main console CLI command handler. Run by the main() thread. */
2015-11-25 20:29:55 +01:00
static void consolehandler ( const char * s )
1999-12-19 22:38:55 +00:00
{
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 );
}
2015-11-25 20:29:55 +01:00
static int remoteconsolehandler ( const 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 );
2013-08-15 16:37:06 +00:00
while ( isspace ( * s )) {
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 , "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
}
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 " ;
2016-03-10 16:58:49 -06:00
ast_cli_allow_at_shutdown ( e );
2007-10-11 19:03:06 +00:00
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 " ;
2016-03-10 16:58:49 -06:00
ast_cli_allow_at_shutdown ( e );
2007-10-11 19:03:06 +00:00
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 " ;
2016-03-10 16:58:49 -06:00
ast_cli_allow_at_shutdown ( e );
2007-10-11 19:03:06 +00:00
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 " ;
2016-03-10 16:58:49 -06:00
ast_cli_allow_at_shutdown ( e );
2007-10-11 19:03:06 +00:00
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 " ;
2016-03-10 16:58:49 -06:00
ast_cli_allow_at_shutdown ( e );
2007-10-11 19:03:06 +00:00
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 " ;
2016-03-10 16:58:49 -06:00
ast_cli_allow_at_shutdown ( e );
2007-10-11 19:03:06 +00:00
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
{
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 " ;
2016-03-10 16:58:49 -06:00
ast_cli_allow_at_shutdown ( e );
2007-10-11 19:03:06 +00:00
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
2015-02-11 17:39:13 +00:00
ast_cancel_shutdown ();
2012-01-15 20:16:08 +00:00
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> "
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_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
2014-01-14 18:14:02 +00:00
static void send_rasterisk_connect_commands ( void )
{
char buf [ 80 ];
/*
* Tell the server asterisk instance about the verbose level
* initially desired.
*/
if ( option_verbose ) {
snprintf ( buf , sizeof ( buf ), "core set verbose atleast %d silent" , option_verbose );
fdsend ( ast_consock , buf );
}
if ( option_debug ) {
snprintf ( buf , sizeof ( buf ), "core set debug atleast %d" , option_debug );
fdsend ( ast_consock , buf );
}
2017-12-13 10:50:59 -05:00
/* Leave verbose filtering to the server. */
option_verbose = INT_MAX ;
2014-01-14 18:14:02 +00:00
if ( ! ast_opt_mute ) {
fdsend ( ast_consock , "logger mute silent" );
} else {
printf ( "log and verbose output currently muted ('logger mute' to unmute) \n " );
}
}
2016-11-14 11:16:03 -07:00
#ifdef HAVE_LIBEDIT_IS_UNICODE
2018-03-17 17:41:13 -04:00
#define CHAR_T_LIBEDIT wchar_t
#define CHAR_TO_LIBEDIT(c) btowc(c)
2016-11-14 11:16:03 -07:00
#else
2018-03-17 17:41:13 -04:00
#define CHAR_T_LIBEDIT char
#define CHAR_TO_LIBEDIT(c) c
2016-11-14 11:16:03 -07:00
#endif
2018-03-17 17:41:13 -04:00
static int ast_el_read_char ( EditLine * editline , CHAR_T_LIBEDIT * cp )
1999-12-19 22:38:55 +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 ];
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 ) {
2018-11-11 08:34:53 -05:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler || sig_flags . need_el_end ) {
2008-12-12 22:04:26 +00:00
break ;
2018-03-17 17:41:13 -04:00
}
if ( errno == EINTR ) {
2003-02-06 06:15:25 +00:00
continue ;
2018-03-17 17:41:13 -04:00
}
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 ) {
2016-11-14 11:16:03 -07:00
char c = '\0' ;
2018-03-17 17:41:13 -04:00
2016-11-14 11:16:03 -07:00
num_read = read ( STDIN_FILENO , & c , 1 );
2003-02-06 06:15:25 +00:00
if ( num_read < 1 ) {
break ;
2011-11-29 18:43:16 +00:00
}
2018-03-17 17:41:13 -04:00
* cp = CHAR_TO_LIBEDIT ( c );
return num_read ;
2003-02-06 06:15:25 +00:00
}
2018-03-17 17:41:13 -04:00
2004-04-25 20:42:45 +00:00
if ( fds [ 0 ]. revents ) {
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 ;
2018-03-17 17:41:13 -04:00
2004-06-25 21:14:03 +00:00
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 ;
2014-01-14 18:14:02 +00:00
send_rasterisk_connect_commands ();
2004-06-25 14:39:38 +00:00
break ;
2018-03-17 17:41:13 -04:00
}
usleep ( 1000000 / reconnects_per_second );
2004-06-25 14:39:38 +00:00
}
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
2016-05-14 07:24:07 -05:00
console_print ( buf );
2012-02-14 20:27:16 +00:00
2016-01-18 10:49:48 +01:00
if (( res < EL_BUF_SIZE - 1 ) && (( buf [ res - 1 ] == '\n' ) || ( res >= 2 && buf [ res - 2 ] == '\n' ))) {
2018-03-17 17:41:13 -04:00
* cp = CHAR_TO_LIBEDIT ( CC_REFRESH );
return 1 ;
2016-01-18 10:49:48 +01:00
}
2018-03-17 17:41:13 -04:00
lastpos = 1 ;
2003-02-06 06:15:25 +00:00
}
}
2018-03-17 17:41:13 -04:00
* cp = CHAR_TO_LIBEDIT ( '\0' );
2016-11-14 11:16:03 -07:00
2018-03-17 17:41:13 -04:00
return 0 ;
1999-12-19 22:38:55 +00:00
}
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 )
2001-05-09 03:11:22 +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 );
}
2003-02-06 06:15:25 +00:00
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 {
2014-05-28 22:54:12 +00:00
ast_str_set ( & prompt , 0 , "%s%s" ,
remotehostname ? remotehostname : "" ,
ASTERISK_PROMPT );
2008-07-30 15:30:18 +00:00
}
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
}
2017-11-20 17:48:22 -05:00
static struct ast_vector_string * ast_el_strtoarr ( char * buf )
2003-02-06 06:15:25 +00:00
{
2013-09-10 18:05:47 +00:00
char * retstr ;
2017-11-07 15:13:57 -05:00
struct ast_vector_string * vec = ast_calloc ( 1 , sizeof ( * vec ));
if ( ! vec ) {
return NULL ;
}
2003-02-06 06:15:25 +00:00
2013-09-10 18:05:47 +00:00
while (( retstr = strsep ( & buf , " " ))) {
if ( ! strcmp ( retstr , AST_CLI_COMPLETE_EOF )) {
2004-04-06 07:42:01 +00:00
break ;
2013-09-10 18:05:47 +00:00
}
2003-02-06 06:15:25 +00:00
2013-09-10 18:05:47 +00:00
retstr = ast_strdup ( retstr );
2017-11-20 17:58:37 -05:00
if ( ! retstr || AST_VECTOR_APPEND ( vec , retstr )) {
2017-11-07 15:13:57 -05:00
ast_free ( retstr );
goto vector_cleanup ;
2013-09-10 18:05:47 +00:00
}
2003-02-06 06:15:25 +00:00
}
2017-11-07 15:13:57 -05:00
if ( ! AST_VECTOR_SIZE ( vec )) {
goto vector_cleanup ;
2013-09-10 18:05:47 +00:00
}
2003-02-06 06:15:25 +00:00
2017-11-20 17:48:22 -05:00
return vec ;
2017-11-07 15:13:57 -05:00
vector_cleanup :
AST_VECTOR_CALLBACK_VOID ( vec , ast_free );
AST_VECTOR_PTR_FREE ( vec );
return NULL ;
2003-02-06 06:15:25 +00:00
}
2017-11-20 17:48:22 -05:00
static void ast_cli_display_match_list ( struct ast_vector_string * matches , int max )
2003-02-06 06:15:25 +00:00
{
2017-11-07 15:47:51 -05:00
int idx = 1 ;
2003-02-06 06:15:25 +00:00
/* find out how many entries can be put on one line, with two spaces between strings */
2017-11-07 15:47:51 -05:00
int limit = ast_get_termcols ( STDOUT_FILENO ) / ( max + 2 );
if ( limit == 0 ) {
2003-02-06 06:15:25 +00:00
limit = 1 ;
2017-11-07 15:47:51 -05:00
}
2003-02-06 06:15:25 +00:00
2017-11-07 15:47:51 -05:00
for (;;) {
int numoutputline ;
2003-02-06 06:15:25 +00:00
2017-11-20 17:48:22 -05:00
for ( numoutputline = 0 ; numoutputline < limit && idx < AST_VECTOR_SIZE ( matches ); idx ++ ) {
2004-10-01 18:35:35 +00:00
numoutputline ++ ;
2017-11-20 17:48:22 -05:00
fprintf ( stdout , "%-*s " , max , AST_VECTOR_GET ( matches , idx ));
2003-02-06 06:15:25 +00:00
}
2017-11-07 15:47:51 -05:00
if ( ! numoutputline ) {
break ;
}
fprintf ( stdout , " \n " );
}
2003-02-06 06:15:25 +00:00
}
2008-08-10 19:35:50 +00:00
static char * cli_complete ( EditLine * editline , int ch )
2003-02-06 06:15:25 +00:00
{
2006-03-31 00:33:28 +00:00
int len = 0 ;
2003-02-06 06:15:25 +00:00
char * ptr ;
2017-11-20 17:48:22 -05:00
struct ast_vector_string * matches ;
2003-02-06 06:15:25 +00:00
int retval = CC_ERROR ;
2017-11-07 16:34:40 -05:00
char 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 ) {
2017-11-07 16:34:40 -05:00
#define CMD_MATCHESARRAY "_COMMAND MATCHESARRAY \"%s\" \"%s\""
char * mbuf ;
char * new_mbuf ;
2017-12-18 21:12:47 -05:00
int mlen = 0 ;
int maxmbuf = ast_asprintf ( & mbuf , CMD_MATCHESARRAY , lf -> buffer , ptr );
2003-02-06 06:15:25 +00:00
2017-12-18 21:12:47 -05:00
if ( maxmbuf == - 1 ) {
2017-11-07 16:34:40 -05:00
* (( char * ) lf -> cursor ) = savechr ;
return ( char * )( CC_ERROR );
}
fdsend ( ast_consock , mbuf );
res = 0 ;
mlen = 0 ;
mbuf [ 0 ] = '\0' ;
while ( ! strstr ( mbuf , AST_CLI_COMPLETE_EOF ) && res != - 1 ) {
if ( mlen + 1024 > maxmbuf ) {
2017-12-18 21:12:47 -05:00
/* Expand buffer to the next 1024 byte increment plus a NULL terminator. */
2017-11-07 16:34:40 -05:00
maxmbuf = mlen + 1024 ;
2017-12-18 21:12:47 -05:00
new_mbuf = ast_realloc ( mbuf , maxmbuf + 1 );
2017-11-07 16:34:40 -05:00
if ( ! new_mbuf ) {
ast_free ( mbuf );
* (( char * ) lf -> cursor ) = savechr ;
return ( char * )( CC_ERROR );
}
mbuf = new_mbuf ;
}
/* Only read 1024 bytes at a time */
res = read ( ast_consock , mbuf + mlen , 1024 );
if ( res > 0 ) {
mlen += res ;
2017-12-18 21:12:47 -05:00
mbuf [ mlen ] = '\0' ;
2017-11-07 16:34:40 -05:00
}
}
mbuf [ mlen ] = '\0' ;
matches = ast_el_strtoarr ( mbuf );
ast_free ( mbuf );
} else {
2017-11-20 17:48:22 -05:00
matches = ast_cli_completion_vector (( char * ) lf -> buffer , ptr );
2003-02-06 06:15:25 +00:00
}
if ( matches ) {
int i ;
2017-11-07 16:34:40 -05:00
int maxlen , match_len ;
2017-11-20 17:48:22 -05:00
const char * best_match = AST_VECTOR_GET ( matches , 0 );
2017-11-07 16:34:40 -05:00
2017-11-20 17:48:22 -05:00
if ( ! ast_strlen_zero ( best_match )) {
2008-08-10 19:35:50 +00:00
el_deletestr ( editline , ( int ) len );
2017-11-20 17:48:22 -05:00
el_insertstr ( editline , best_match );
2003-02-06 06:15:25 +00:00
retval = CC_REFRESH ;
}
2017-11-20 17:48:22 -05:00
if ( AST_VECTOR_SIZE ( matches ) == 2 ) {
2003-02-06 06:15:25 +00:00
/* 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 */
2017-11-20 17:48:22 -05:00
for ( i = 1 , maxlen = 0 ; i < AST_VECTOR_SIZE ( matches ); i ++ ) {
match_len = strlen ( AST_VECTOR_GET ( matches , i ));
2017-11-07 16:34:40 -05:00
if ( match_len > maxlen ) {
2003-02-06 06:15:25 +00:00
maxlen = match_len ;
2017-11-07 16:34:40 -05:00
}
2003-02-06 06:15:25 +00:00
}
2017-11-07 16:34:40 -05:00
fprintf ( stdout , " \n " );
ast_cli_display_match_list ( matches , maxlen );
retval = CC_REDISPLAY ;
2003-02-06 06:15:25 +00:00
}
2017-11-20 17:48:22 -05:00
AST_VECTOR_CALLBACK_VOID ( matches , ast_free );
AST_VECTOR_PTR_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
2015-11-25 20:29:55 +01:00
static int ast_el_add_history ( const char * buf )
2003-02-06 06:15:25 +00:00
{
HistEvent ev ;
2013-08-22 12:28:33 +00:00
char * stripped_buf ;
2003-02-06 06:15:25 +00:00
2013-08-22 12:28:33 +00:00
if ( el_hist == NULL || el == NULL ) {
2003-02-06 06:15:25 +00:00
ast_el_initialize ();
2013-08-22 12:28:33 +00:00
}
if ( strlen ( buf ) > ( MAX_HISTORY_COMMAND_LENGTH - 1 )) {
2004-01-23 19:12:44 +00:00
return 0 ;
2013-08-22 12:28:33 +00:00
}
stripped_buf = ast_strip ( ast_strdupa ( buf ));
/* HISTCONTROL=ignoredups */
if ( ! history ( el_hist , & ev , H_FIRST ) && strcmp ( ev . str , stripped_buf ) == 0 ) {
return 0 ;
}
return history ( el_hist , & ev , H_ENTER , stripped_buf );
2003-02-06 06:15:25 +00:00
}
2015-11-25 20:29:55 +01:00
static int ast_el_write_history ( const char * filename )
2003-02-06 06:15:25 +00:00
{
HistEvent ev ;
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
return ( history ( el_hist , & ev , H_SAVE , filename ));
}
2015-11-25 20:29:55 +01:00
static int ast_el_read_history ( const char * filename )
2003-02-06 06:15:25 +00:00
{
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
}
2015-11-25 20:29:55 +01:00
static void ast_el_read_default_histfile ( void )
{
char histfile [ 80 ] = "" ;
const char * home = getenv ( "HOME" );
if ( ! ast_strlen_zero ( home )) {
snprintf ( histfile , sizeof ( histfile ), "%s/.asterisk_history" , home );
ast_el_read_history ( histfile );
}
}
static void ast_el_write_default_histfile ( void )
{
char histfile [ 80 ] = "" ;
const char * home = getenv ( "HOME" );
if ( ! ast_strlen_zero ( home )) {
snprintf ( histfile , sizeof ( histfile ), "%s/.asterisk_history" , home );
ast_el_write_history ( histfile );
}
}
2008-11-02 18:52:13 +00:00
static void ast_remotecontrol ( char * data )
2001-05-09 03:11:22 +00:00
{
2014-12-09 20:47:05 +00:00
char buf [ 256 ] = "" ;
2001-05-09 03:11:22 +00:00
int res ;
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 ;
2015-11-25 20:29:55 +01:00
ast_term_init ();
printf ( "%s" , term_end ());
fflush ( stdout );
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 );
2014-12-09 20:47:05 +00:00
if ( read ( ast_consock , buf , sizeof ( buf ) - 1 ) < 0 ) {
2008-11-02 18:52:13 +00:00
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 ));
2018-11-11 08:34:53 -05:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler || sig_flags . need_el_end ) {
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 ) {
2014-01-14 18:14:02 +00:00
send_rasterisk_connect_commands ();
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 ;
2018-11-11 08:34:53 -05:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler || sig_flags . need_el_end ) {
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 );
2021-03-19 10:11:26 -04:00
ast_init_logger_for_socket_console ();
2008-11-05 22:19:18 +00:00
remotehostname = hostname ;
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
2015-11-25 20:29:55 +01:00
ast_el_read_default_histfile ();
2008-11-05 22:19:18 +00:00
el_set ( el , EL_GETCFN , ast_el_read_char );
2006-03-31 00:33:28 +00:00
for (;;) {
2003-02-06 06:15:25 +00:00
ebuf = ( char * ) el_gets ( el , & num );
2018-11-11 08:34:53 -05:00
if ( sig_flags . need_quit || sig_flags . need_quit_handler || sig_flags . need_el_end ) {
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 )
{
2018-07-20 15:52:12 -05:00
printf ( "Asterisk %s, Copyright (C) 1999 - 2018, 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 " );
2015-05-06 09:31:33 -04:00
printf ( " -d Increase debugging (multiple d's = more 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 " );
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 " );
2015-05-06 09:31:33 -04:00
printf ( " -X Enable use of #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 ;
}
2016-11-23 18:27:54 -06:00
static void read_pjproject_startup_options ( void )
{
struct ast_config * cfg ;
struct ast_variable * v ;
struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE | CONFIG_FLAG_NOREALTIME };
ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL ;
2018-02-27 15:40:18 -06:00
ast_option_pjproject_cache_pools = DEFAULT_PJPROJECT_CACHE_POOLS ;
2016-11-23 18:27:54 -06:00
cfg = ast_config_load2 ( "pjproject.conf" , "" /* core, can't reload */ , config_flags );
if ( ! cfg
|| cfg == CONFIG_STATUS_FILEUNCHANGED
|| cfg == CONFIG_STATUS_FILEINVALID ) {
/* We'll have to use defaults */
return ;
}
for ( v = ast_variable_browse ( cfg , "startup" ); v ; v = v -> next ) {
if ( ! strcasecmp ( v -> name , "log_level" )) {
if ( sscanf ( v -> value , "%30d" , & ast_option_pjproject_log_level ) != 1 ) {
ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL ;
} else if ( ast_option_pjproject_log_level < 0 ) {
ast_option_pjproject_log_level = 0 ;
} else if ( MAX_PJ_LOG_MAX_LEVEL < ast_option_pjproject_log_level ) {
ast_option_pjproject_log_level = MAX_PJ_LOG_MAX_LEVEL ;
}
2018-02-27 15:40:18 -06:00
} else if ( ! strcasecmp ( v -> name , "cache_pools" )) {
ast_option_pjproject_cache_pools = ! ast_false ( v -> value );
2016-11-23 18:27:54 -06:00
}
}
ast_config_destroy ( cfg );
}
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 };
2017-11-09 20:47:27 -05:00
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
}
2017-11-09 20:47:27 -05:00
ast_alertpipe_read ( sig_alert_pipe );
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 " );
2016-09-19 16:40:40 +02:00
set_priority_all ( 0 );
2007-12-18 23:06:05 +00:00
pthread_exit ( NULL );
}
/* Check the canary once a minute */
sleep ( 60 );
}
}
/* Used by libc's atexit(3) function */
static void canary_exit ( void )
{
2016-09-19 21:21:23 +02:00
if ( canary_pid > 0 ) {
int status ;
2007-12-18 23:06:05 +00:00
kill ( canary_pid , SIGKILL );
2016-09-19 21:21:23 +02:00
waitpid ( canary_pid , & status , 0 );
}
2007-12-18 23:06:05 +00:00
}
2014-01-14 18:14:02 +00:00
/* Execute CLI commands on startup. Run by main() thread. */
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-03-26 18:39:06 +00:00
if ( ! ( cfg = ast_config_load2 ( "cli.conf" , "" /* core, can't reload */ , cfg_flags )))
2008-01-22 20:33:16 +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-22 20:33:16 +00:00
2008-01-17 00:05:13 +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-17 00:05:13 +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-08-29 22:49:24 +00:00
if ( ast_opt_console || option_verbose || ( ast_opt_remote && ! ast_opt_exec )) {
2012-11-18 20:27:45 +00:00
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 ;
2002-05-14 14:43:52 +00:00
int x ;
2010-06-28 21:50:57 +00:00
int isroot = 1 , rundir_exists = 0 ;
2019-10-23 12:36:17 -05:00
RAII_VAR ( char * , runuser , NULL , ast_free );
RAII_VAR ( char * , rungroup , NULL , ast_free );
RAII_VAR ( char * , xarg , NULL , ast_free );
2010-09-02 05:02:54 +00:00
struct rlimit l ;
2015-05-06 09:31:33 -04:00
static const char * getopt_settings = "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:" ;
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
}
2004-03-20 21:13:12 +00:00
ast_mainpid = getpid ();
2007-10-17 15:39:24 +00:00
2015-05-06 09:31:33 -04:00
/* Process command-line options that effect asterisk.conf load. */
while (( c = getopt ( argc , argv , getopt_settings )) != - 1 ) {
switch ( c ) {
case 'X' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_EXEC_INCLUDES );
break ;
case 'C' :
2018-03-21 23:00:56 -04:00
set_asterisk_conf_path ( optarg );
2015-05-06 09:31:33 -04:00
break ;
case 'd' :
option_debug ++ ;
break ;
case 'h' :
show_cli_help ();
exit ( 0 );
case 'R' :
case 'r' :
case 'x' :
/* ast_opt_remote is checked during config load. This is only part of what
* these options do, see the second loop for the rest of the actions. */
ast_set_flag ( & ast_options , AST_OPT_FLAG_REMOTE );
break ;
case 'V' :
show_version ();
exit ( 0 );
case 'v' :
option_verbose ++ ;
break ;
case '?' :
exit ( 1 );
}
}
/* Initialize env so it is available if #exec is used in asterisk.conf. */
env_init ();
2018-03-21 23:00:56 -04:00
load_asterisk_conf ();
2015-05-06 09:31:33 -04:00
/* Update env to include any systemname that was set. */
env_init ();
2012-09-21 17:14:59 +00:00
/*! \brief Check for options
*
* \todo Document these options
*/
2018-03-26 14:42:52 +02:00
optind = 1 ;
2015-05-06 09:31:33 -04:00
while (( c = getopt ( argc , argv , getopt_settings )) != - 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' :
2015-05-06 09:31:33 -04:00
/* The command-line -X option enables #exec for asterisk.conf only. */
2009-12-02 20:10:07 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'C' :
2015-05-06 09:31:33 -04:00
/* already processed. */
2009-11-26 02:09:58 +00:00
break ;
case 'c' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE );
break ;
case 'd' :
2015-05-06 09:31:33 -04:00
/* already processed. */
2009-11-26 02:09:58 +00:00
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' :
2019-10-23 12:36:17 -05:00
rungroup = ast_strdup ( optarg );
2001-12-25 21:12:07 +00:00
break ;
2006-03-31 00:33:28 +00:00
case 'g' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_DUMP_CORE );
2003-02-06 06:15:25 +00:00
break ;
2002-09-12 03:22:07 +00:00
case 'h' :
2015-05-06 09:31:33 -04:00
/* already processed. */
break ;
2014-04-08 21:25:15 +00:00
case 'I' :
fprintf ( stderr ,
"NOTICE: The -I option is no longer needed. \n "
" It will always be enabled if you have a timing module loaded. \n " );
break ;
2009-11-26 02:09:58 +00:00
case 'i' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_INIT_KEYS );
break ;
case 'L' :
2013-08-05 14:35:00 +00:00
if (( sscanf ( optarg , "%30lf" , & ast_option_maxload ) != 1 ) || ( ast_option_maxload < 0.0 )) {
ast_option_maxload = 0.0 ;
2009-11-26 02:09:58 +00:00
}
break ;
case 'M' :
2013-08-05 14:35:00 +00:00
if (( sscanf ( optarg , "%30d" , & ast_option_maxcalls ) != 1 ) || ( ast_option_maxcalls < 0 )) {
ast_option_maxcalls = 0 ;
2009-11-26 02:09:58 +00:00
}
break ;
case 'm' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_MUTE );
break ;
case 'n' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_COLOR );
break ;
case 'p' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_HIGH_PRIORITY );
break ;
case 'q' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_QUIET );
break ;
case 'R' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT );
break ;
case 'r' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE );
2004-07-18 16:20:54 +00:00
break ;
2007-12-19 07:01:40 +00:00
case 's' :
2015-05-06 09:31:33 -04:00
if ( ast_opt_remote ) {
2018-03-21 23:00:56 -04:00
set_socket_path ( optarg );
2015-05-06 09:31:33 -04:00
}
2007-12-19 07:01:40 +00:00
break ;
2009-11-26 02:09:58 +00:00
case 'T' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_TIMESTAMP );
break ;
case 't' :
ast_set_flag ( & ast_options , AST_OPT_FLAG_CACHE_RECORD_FILES );
break ;
case 'U' :
2019-10-23 12:36:17 -05:00
runuser = ast_strdup ( optarg );
2009-11-26 02:09:58 +00:00
break ;
case 'V' :
case 'v' :
2015-05-06 09:31:33 -04:00
/* already processed. */
2009-11-26 02:09:58 +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 );
2019-10-23 12:36:17 -05:00
xarg = ast_strdup ( optarg );
2008-08-25 23:13:32 +00:00
break ;
1999-11-15 04:57:28 +00:00
case '?' :
2015-05-06 09:31:33 -04:00
/* already processed. */
break ;
1999-11-15 04:57:28 +00:00
}
}
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 ;
}
}
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 ))
2019-10-23 12:36:17 -05:00
rungroup = ast_strdup ( ast_config_AST_RUN_GROUP );
2005-11-08 00:30:29 +00:00
if (( ! runuser ) && ! ast_strlen_zero ( ast_config_AST_RUN_USER ))
2019-10-23 12:36:17 -05:00
runuser = ast_strdup ( 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)
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
2014-01-14 18:14:02 +00:00
/* Initial value of the maximum active system verbosity level. */
ast_verb_sys_level = option_verbose ;
2017-06-18 20:24:04 -04:00
if ( ast_sd_get_fd_un ( SOCK_STREAM , ast_config_AST_SOCKET ) > 0 ) {
ast_socket_is_sd = 1 ;
}
/* DO NOT perform check for existing daemon if systemd has CLI socket activation */
if ( ! ast_socket_is_sd && ast_tryconnect ()) {
2001-05-09 03:11:22 +00:00
/* 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 );
}
2015-11-25 20:29:55 +01:00
ast_term_init ();
printf ( "%s" , term_end ());
fflush ( stdout );
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
2020-04-14 18:02:19 +02:00
#ifdef HAVE_CAP
child_cap = cap_from_text ( "cap_net_admin-eip" );
#endif
2015-11-25 20:29:55 +01:00
/* Not a remote console? Start the daemon. */
asterisk_daemon ( isroot , runuser , rungroup );
2020-04-14 18:02:19 +02:00
#ifdef HAS_CAP
cap_free ( child_cap );
#endif
2015-11-25 20:29:55 +01:00
return 0 ;
}
2016-08-11 23:12:32 -04:00
static inline void check_init ( int init_result , const char * name )
{
if ( init_result ) {
2017-04-11 10:07:39 -06:00
if ( ast_is_logger_initialized ()) {
ast_log ( LOG_ERROR , "%s initialization failed. ASTERISK EXITING! \n %s" , name , term_quit ());
} else {
fprintf ( stderr , "%s initialization failed. ASTERISK EXITING! \n %s" , name , term_quit ());
}
2016-08-11 23:12:32 -04:00
ast_run_atexits ( 0 );
exit ( init_result == - 2 ? 2 : 1 );
}
}
2015-11-25 20:29:55 +01:00
static void asterisk_daemon ( int isroot , const char * runuser , const char * rungroup )
{
FILE * f ;
sigset_t sigs ;
int num ;
char * buf ;
2016-07-23 07:51:48 -06:00
char pbx_uuid [ AST_UUID_STR_LEN ];
2015-11-25 20:29:55 +01:00
2016-05-25 15:45:08 +02:00
/* Set time as soon as possible */
ast_lastreloadtime = ast_startuptime = ast_tvnow ();
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 ;
2018-08-01 00:54:11 -04:00
load_astmm_phase_1 ();
2012-11-29 00:48:12 +00:00
2016-09-19 21:21:23 +02:00
/* Check whether high prio was succesfully set by us or some
* other incantation. */
if ( has_priority ()) {
ast_set_flag ( & ast_options , AST_OPT_FLAG_HIGH_PRIORITY );
} else {
ast_clear_flag ( & ast_options , AST_OPT_FLAG_HIGH_PRIORITY );
}
2009-05-18 19:17:15 +00:00
/* Spawning of astcanary must happen AFTER the call to daemon(3) */
2016-09-19 21:21:23 +02:00
if ( ast_opt_high_priority ) {
2009-05-18 19:17:15 +00:00
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 );
register_config_cli ();
2016-08-11 23:12:32 -04:00
check_init ( astobj2_init (), "AO2" );
check_init ( ast_named_locks_init (), "Named Locks" );
2016-03-31 19:04:29 -06:00
2012-11-18 20:27:45 +00:00
if ( ast_opt_console ) {
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
2015-11-25 20:29:55 +01:00
ast_el_read_default_histfile ();
2012-11-18 20:27:45 +00:00
}
2016-07-23 07:51:48 -06:00
#ifdef AST_XML_DOCS
/* Load XML documentation. */
ast_xmldoc_load_documentation ();
#endif
2016-08-11 23:12:32 -04:00
check_init ( astdb_init (), "ASTdb" );
2016-07-23 07:51:48 -06:00
ast_uuid_init ();
if ( ast_pbx_uuid_get ( pbx_uuid , sizeof ( pbx_uuid ))) {
ast_uuid_generate_str ( pbx_uuid , sizeof ( pbx_uuid ));
ast_db_put ( "pbx" , "UUID" , pbx_uuid );
}
ast_verb ( 0 , "PBX UUID: %s \n " , pbx_uuid );
2019-03-07 18:17:49 -05:00
check_init ( ast_json_init (), "libjansson" );
2012-11-18 20:27:45 +00:00
ast_ulaw_init ();
ast_alaw_init ();
2020-07-13 16:06:14 -04:00
ast_utf8_init ();
2012-11-18 20:27:45 +00:00
tdd_init ();
callerid_init ();
ast_builtins_init ();
2016-08-11 23:12:32 -04:00
check_init ( ast_utils_init (), "Utilities" );
check_init ( ast_tps_init (), "Task Processor Core" );
check_init ( ast_fd_init (), "File Descriptor Debugging" );
check_init ( ast_pbx_init (), "ast_pbx_init" );
2018-11-30 07:40:40 -04:00
check_init ( aco_init (), "Configuration Option Framework" );
check_init ( stasis_init (), "Stasis" );
2009-12-22 16:09:11 +00:00
#ifdef TEST_FRAMEWORK
2016-08-11 23:12:32 -04:00
check_init ( ast_test_init (), "Test Framework" );
2009-12-22 16:09:11 +00:00
#endif
2016-08-11 23:12:32 -04:00
check_init ( ast_translate_init (), "Translator Core" );
2011-02-03 16:22:10 +00:00
2010-06-02 18:10:15 +00:00
ast_aoc_cli_init ();
2016-08-11 23:12:32 -04:00
check_init ( ast_sorcery_init (), "Sorcery" );
check_init ( ast_codec_init (), "Codecs" );
check_init ( ast_format_init (), "Formats" );
check_init ( ast_format_cache_init (), "Format Cache" );
check_init ( ast_codec_builtin_init (), "Built-in Codecs" );
check_init ( ast_bucket_init (), "Bucket API" );
check_init ( ast_stasis_system_init (), "Stasis system-level information" );
check_init ( ast_endpoint_stasis_init (), "Stasis Endpoint" );
2013-05-08 13:39:08 +00:00
2001-05-09 03:11:22 +00:00
ast_makesocket ();
2015-01-26 14:50:40 +00:00
/* GCC 4.9 gives a bogus "right-hand operand of comma expression has
* no effect" warning */
( void ) sigemptyset ( & sigs );
( void ) sigaddset ( & sigs , SIGHUP );
( void ) sigaddset ( & sigs , SIGTERM );
( void ) sigaddset ( & sigs , SIGINT );
( void ) sigaddset ( & sigs , SIGPIPE );
( void ) sigaddset ( & sigs , SIGWINCH );
2001-05-09 03:11:22 +00:00
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
2007-01-04 23:18:36 +00:00
threadstorage_init ();
2016-09-20 10:22:45 -04:00
check_init ( init_logger (), "Logger" );
2016-08-11 23:12:32 -04:00
check_init ( ast_rtp_engine_init (), "RTP Engine" );
2011-02-03 16:22:10 +00:00
2008-03-03 15:59:50 +00:00
ast_autoservice_init ();
2016-08-11 23:12:32 -04:00
check_init ( ast_timing_init (), "Timing" );
check_init ( ast_ssl_init (), "SSL" );
2016-11-23 18:27:54 -06:00
read_pjproject_startup_options ();
2016-08-11 23:12:32 -04:00
check_init ( ast_pj_init (), "Embedded PJProject" );
check_init ( app_init (), "App Core" );
2019-04-09 13:48:49 -05:00
check_init ( mwi_init (), "MWI Core" );
2016-08-11 23:12:32 -04:00
check_init ( devstate_init (), "Device State Core" );
check_init ( ast_msg_init (), "Messaging API" );
check_init ( ast_channels_init (), "Channel" );
check_init ( ast_endpoint_init (), "Endpoints" );
check_init ( ast_pickup_init (), "Call Pickup" );
check_init ( ast_bridging_init (), "Bridging" );
check_init ( ast_parking_stasis_init (), "Parking Core" );
check_init ( ast_device_state_engine_init (), "Device State Engine" );
check_init ( ast_presence_state_engine_init (), "Presence State Engine" );
2018-03-10 04:33:33 -05:00
check_init ( dns_core_init (), "DNS Resolver Core" );
2016-08-11 23:12:32 -04:00
check_init ( ast_dns_system_resolver_init (), "Default DNS resolver" );
check_init ( ast_security_stasis_init (), "Security Stasis Topic and Events" );
check_init ( ast_image_init (), "Image" );
check_init ( ast_file_init (), "Generic File Format Support" );
check_init ( load_pbx (), "load_pbx" );
check_init ( load_pbx_builtins (), "Builtin PBX Applications" );
check_init ( load_pbx_functions_cli (), "PBX Functions Support" );
check_init ( load_pbx_variables (), "PBX Variables Support" );
check_init ( load_pbx_switch (), "PBX Switch Support" );
check_init ( load_pbx_app (), "PBX Application Support" );
check_init ( load_pbx_hangup_handler (), "PBX Hangup Handler Support" );
check_init ( ast_local_init (), "Local Proxy Channel Driver" );
2018-01-01 16:59:57 -05:00
/* We should avoid most config loads before this point as they can't use realtime. */
2018-07-15 14:58:15 -04:00
check_init ( load_modules (), "Module" );
2006-08-21 22:23:26 +00:00
2015-01-29 14:38:23 +00:00
/*
* This has to load after the dynamic modules load, as items in the media
* cache can't be constructed from items in the AstDB without their
* bucket backends.
*/
2016-08-11 23:12:32 -04:00
check_init ( ast_media_cache_init (), "Media Cache" );
2015-01-29 14:38:23 +00:00
2021-10-30 21:04:30 -04:00
/* loads the cli_permissions.conf file needed to implement cli restrictions. */
2008-12-01 18:52:14 +00:00
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 ();
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
2017-11-09 20:47:27 -05:00
ast_alertpipe_init ( sig_alert_pipe );
2007-02-23 23:25:22 +00:00
2015-04-09 23:08:10 +00:00
ast_process_pending_reloads ();
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_FULLY_BOOTED );
2013-05-24 20:44:07 +00:00
publish_fully_booted ();
2009-06-04 14:31:24 +00:00
2001-05-09 03:11:22 +00:00
pthread_sigmask ( SIG_UNBLOCK , & sigs , NULL );
2006-08-21 02:11:39 +00:00
2018-08-01 00:54:11 -04:00
load_astmm_phase_2 ();
2006-08-21 02:11:39 +00:00
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 ));
2015-03-26 22:24:26 +00:00
ast_register_cleanup ( main_atexit );
2006-08-21 02:11:39 +00:00
2008-01-17 00:05:13 +00:00
run_startup_commands ();
2016-06-27 21:26:54 +02:00
ast_sd_notify ( "READY=1" );
2008-01-17 00:05:13 +00:00
2014-05-28 22:54:12 +00:00
ast_verb ( 0 , COLORIZE_FMT " \n " , COLORIZE ( COLOR_BRGREEN , 0 , "Asterisk Ready." ));
2014-12-22 20:08:35 +00:00
logger_queue_start ();
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 ];
2015-11-25 20:29:55 +01:00
char hostname [ MAXHOSTNAMELEN ] = "" ;
if ( gethostname ( hostname , sizeof ( hostname ) - 1 )) {
ast_copy_string ( hostname , "<Unknown>" , sizeof ( hostname ));
}
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 (;;) {
2018-11-11 08:34:53 -05:00
if ( sig_flags . need_el_end ) {
el_end ( el );
return ;
}
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 )
2015-11-25 20:29:55 +01:00
return ; /* quit */
2007-06-27 23:30:31 +00:00
2007-06-24 20:07:15 +00:00
if ( buf ) {
if ( buf [ strlen ( buf ) - 1 ] == '\n' )
buf [ strlen ( buf ) - 1 ] = '\0' ;
2003-02-06 06:15:25 +00:00
2015-11-25 20:29:55 +01:00
consolehandler ( buf );
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
2015-11-25 20:29:55 +01:00
/* Stall until a quit signal is given */
2007-02-23 23:25:22 +00:00
monitor_sig_flags ( NULL );
1999-11-15 04:57:28 +00:00
}