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
*
2006-03-25 23:22:44 +00:00
* Copyright (C) 1999 - 2006, 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 */
/*!
* \mainpage Asterisk -- An Open Source Telephony Toolkit
*
2005-11-14 19:00:38 +00:00
* \par Developer Documentation for Asterisk
* This is the main developer documentation for Asterisk. It is
* generated by running "make progdocs".
* \par Additional documentation
2005-10-24 20:12:06 +00:00
* \arg \ref DevDoc
* \arg \ref ConfigFiles
*
* \section copyright Copyright and author
*
2006-03-31 00:33:28 +00:00
* Copyright (C) 1999 - 2006, Digium, Inc.
2005-10-24 20:12:06 +00:00
* Asterisk is a trade mark registered by Digium, Inc.
*
* \author Mark Spencer <markster@digium.com>
* Also see \ref AstCREDITS
*
* \section license License
* 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.
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*
* \verbinclude LICENSE
*
*/
/*! \file
\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
*/
2006-06-07 18:54:56 +00:00
#include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , "$Revision$" )
1999-11-15 04:57:28 +00:00
#include <unistd.h>
#include <stdlib.h>
2005-04-29 17:24:58 +00:00
#include <sys/time.h>
2005-04-22 13:11:34 +00:00
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
#include <sched.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <sys/resource.h>
#include <grp.h>
#include <pwd.h>
#include <sys/stat.h>
2006-04-12 20:40:46 +00:00
#ifdef linux
#include <sys/prctl.h>
2006-09-27 21:48:01 +00:00
#ifdef HAVE_CAP
#include <sys/capability.h>
#endif /* HAVE_CAP */
#endif /* linux */
2005-06-06 20:27:51 +00:00
#include <regex.h>
2005-04-22 13:11:34 +00:00
#if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
#include <netdb.h>
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 */
2006-03-02 22:27:50 +00:00
#endif
2005-04-22 13:11:34 +00:00
#endif
2005-04-21 06:02:45 +00:00
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"
#include "asterisk/channel.h"
#include "asterisk/ulaw.h"
#include "asterisk/alaw.h"
#include "asterisk/callerid.h"
#include "asterisk/image.h"
#include "asterisk/tdd.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
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/enum.h"
#include "asterisk/rtp.h"
2006-03-25 23:50:09 +00:00
#include "asterisk/http.h"
2006-01-12 17:14:58 +00:00
#include "asterisk/udptl.h"
2005-04-21 06:02:45 +00:00
#include "asterisk/app.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/io.h"
#include "asterisk/lock.h"
2003-02-06 06:15:25 +00:00
#include "editline/histedit.h"
2005-04-21 06:02:45 +00:00
#include "asterisk/config.h"
2005-06-06 03:04:58 +00:00
#include "asterisk/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"
2005-06-06 03:04:58 +00:00
2005-10-24 20:12:06 +00:00
#include "asterisk/doxyref.h" /* Doxygen documentation */
2006-08-21 02:11:39 +00:00
#include "../defaults.h"
2004-04-28 13:53:01 +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 \
2007-02-13 06:02:57 +00:00
ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n" \
"Created by Mark Spencer <markster@digium.com>\n" \
"Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
"This is free software, with components licensed under the GNU General Public\n" \
"License version 2 and other licenses; you are welcome to redistribute it under\n" \
"certain conditions. Type 'core show license' for details.\n" \
"=========================================================================\n" \
"NOTE: This is a development version of Asterisk, and should not be used in\n" \
"production installations.\n");
2004-06-25 21:14:03 +00:00
2006-10-30 16:33:02 +00:00
/*! \defgroup main_options Main Configuration Options
2005-11-14 19:00:38 +00:00
\brief Main configuration options from \ref Config_ast "asterisk.conf" or
the operating system command line when starting Asterisk
Some of them can be changed in the CLI
*/
/*! @{ */
2005-12-04 20:40:46 +00:00
2006-03-14 16:57:35 +00:00
struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
2005-12-04 20:40:46 +00:00
2006-12-27 22:14:33 +00:00
int option_verbose ; /*!< Verbosity level */
int option_debug ; /*!< Debug level */
2005-12-04 20:40:46 +00:00
2006-12-27 22:14:33 +00:00
double option_maxload ; /*!< Max load avg on system */
int option_maxcalls ; /*!< Max number of active calls */
2007-02-14 20:22:20 +00:00
int option_maxfiles ; /*!< Max number of open file handles (files, sockets) */
2005-11-14 19:00:38 +00:00
/*! @} */
2004-09-07 15:02:53 +00:00
char record_cache_dir [ AST_CACHE_DIR_LEN ] = AST_TMP_DIR ;
2005-03-05 04:04:55 +00:00
char debug_filename [ AST_FILENAME_MAX ] = "" ;
1999-12-19 22:38:55 +00:00
2005-10-24 20:12:06 +00:00
static int ast_socket = - 1 ; /*!< UNIX Socket for allowing remote control */
static int ast_consock = - 1 ; /*!< UNIX Socket for controlling another asterisk */
2006-05-08 12:32:44 +00:00
pid_t ast_mainpid ;
2001-05-09 03:11:22 +00:00
struct console {
2005-10-24 20:12:06 +00:00
int fd ; /*!< File descriptor */
int p [ 2 ]; /*!< Pipe */
pthread_t t ; /*!< Thread of handler */
2006-05-26 19:48:17 +00:00
int mute ; /*!< Is the console muted for logs */
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 );
2006-01-24 20:27:09 +00:00
AST_LIST_ENTRY ( ast_atexit ) list ;
};
2005-10-24 20:12:06 +00:00
2006-01-24 20:27:09 +00:00
static AST_LIST_HEAD_STATIC ( atexits , ast_atexit );
2003-08-07 03:48:00 +00:00
2003-05-02 15:37:34 +00:00
time_t ast_startuptime ;
time_t ast_lastreloadtime ;
2006-12-27 22:14:33 +00:00
static History * el_hist ;
static EditLine * el ;
2003-02-06 06:15:25 +00:00
static char * remotehostname ;
2001-05-09 03:11:22 +00:00
struct console consoles [ AST_MAX_CONNECTS ];
2000-01-09 19:58:18 +00:00
char defaultlanguage [ MAX_LANGUAGE ] = DEFAULT_LANGUAGE ;
2003-02-06 06:15:25 +00:00
static int ast_el_add_history ( char * );
static int ast_el_read_history ( char * );
static int ast_el_write_history ( char * );
2006-06-09 20:40:10 +00:00
char ast_config_AST_CONFIG_DIR [ PATH_MAX ];
char ast_config_AST_CONFIG_FILE [ PATH_MAX ];
char ast_config_AST_MODULE_DIR [ PATH_MAX ];
char ast_config_AST_SPOOL_DIR [ PATH_MAX ];
char ast_config_AST_MONITOR_DIR [ PATH_MAX ];
char ast_config_AST_VAR_DIR [ PATH_MAX ];
char ast_config_AST_DATA_DIR [ PATH_MAX ];
char ast_config_AST_LOG_DIR [ PATH_MAX ];
char ast_config_AST_AGI_DIR [ PATH_MAX ];
char ast_config_AST_DB [ PATH_MAX ];
char ast_config_AST_KEY_DIR [ PATH_MAX ];
char ast_config_AST_PID [ PATH_MAX ];
char ast_config_AST_SOCKET [ PATH_MAX ];
char ast_config_AST_RUN_DIR [ PATH_MAX ];
char ast_config_AST_RUN_USER [ PATH_MAX ];
char ast_config_AST_RUN_GROUP [ PATH_MAX ];
char ast_config_AST_CTL_PERMISSIONS [ PATH_MAX ];
char ast_config_AST_CTL_OWNER [ PATH_MAX ] = " \0 " ;
char ast_config_AST_CTL_GROUP [ PATH_MAX ] = " \0 " ;
char ast_config_AST_CTL [ PATH_MAX ] = "asterisk.ctl" ;
2006-03-31 00:33:28 +00:00
char ast_config_AST_SYSTEM_NAME [ 20 ] = "" ;
2003-02-06 06:15:25 +00:00
2006-04-29 00:15:28 +00:00
extern const char * ast_build_hostname ;
extern const char * ast_build_kernel ;
extern const char * ast_build_machine ;
extern const char * ast_build_os ;
extern const char * ast_build_date ;
extern const char * ast_build_user ;
2004-02-23 03:43:21 +00:00
static char * _argv [ 256 ];
2006-12-27 22:14:33 +00:00
static int shuttingdown ;
static int restartnow ;
2004-03-15 07:51:22 +00:00
static pthread_t consolethread = AST_PTHREADT_NULL ;
2004-02-23 03:43:21 +00:00
2006-01-10 00:55:45 +00:00
static char randompool [ 256 ];
2007-01-30 17:23:56 +00:00
static unsigned int need_reload ;
2005-06-07 16:07:06 +00:00
#if !defined(LOW_MEMORY)
2005-06-06 20:27:51 +00:00
struct file_version {
AST_LIST_ENTRY ( file_version ) list ;
2005-06-06 21:09:59 +00:00
const char * file ;
char * version ;
2005-06-06 20:27:51 +00:00
};
static AST_LIST_HEAD_STATIC ( file_versions , file_version );
void ast_register_file_version ( const char * file , const char * version )
{
struct file_version * new ;
2005-06-06 21:09:59 +00:00
char * work ;
size_t version_length ;
2005-06-06 20:27:51 +00:00
2005-06-06 21:09:59 +00:00
work = ast_strdupa ( version );
work = ast_strip ( ast_strip_quoted ( work , "$" , "$" ));
version_length = strlen ( work ) + 1 ;
2006-02-14 22:28:01 +00:00
if ( ! ( new = ast_calloc ( 1 , sizeof ( * new ) + version_length )))
2005-06-06 20:27:51 +00:00
return ;
new -> file = file ;
2005-06-06 21:09:59 +00:00
new -> version = ( char * ) new + sizeof ( * new );
memcpy ( new -> version , work , version_length );
2005-06-06 20:27:51 +00:00
AST_LIST_LOCK ( & file_versions );
AST_LIST_INSERT_HEAD ( & file_versions , new , list );
AST_LIST_UNLOCK ( & file_versions );
}
void ast_unregister_file_version ( const char * file )
{
struct file_version * find ;
AST_LIST_LOCK ( & file_versions );
AST_LIST_TRAVERSE_SAFE_BEGIN ( & file_versions , find , list ) {
if ( ! strcasecmp ( find -> file , file )) {
AST_LIST_REMOVE_CURRENT ( & file_versions , list );
break ;
}
}
AST_LIST_TRAVERSE_SAFE_END ;
AST_LIST_UNLOCK ( & file_versions );
2005-06-06 21:09:59 +00:00
if ( find )
free ( find );
2005-06-06 20:27:51 +00:00
}
2006-04-12 20:40:46 +00:00
struct thread_list_t {
AST_LIST_ENTRY ( thread_list_t ) list ;
char * name ;
pthread_t id ;
};
static AST_LIST_HEAD_STATIC ( thread_list , thread_list_t );
2006-12-06 07:23:32 +00:00
static const char show_threads_help [] =
2006-11-02 23:16:09 +00:00
"Usage: core show threads \n "
2006-04-12 20:40:46 +00:00
" List threads currently active in the system. \n " ;
void ast_register_thread ( char * name )
{
struct thread_list_t * new = ast_calloc ( 1 , sizeof ( * new ));
if ( ! new )
return ;
new -> id = pthread_self ();
2006-10-04 19:51:38 +00:00
new -> name = name ; /* steal the allocated memory for the thread name */
2006-04-12 20:40:46 +00:00
AST_LIST_LOCK ( & thread_list );
AST_LIST_INSERT_HEAD ( & thread_list , new , list );
AST_LIST_UNLOCK ( & thread_list );
}
void ast_unregister_thread ( void * id )
{
struct thread_list_t * x ;
AST_LIST_LOCK ( & thread_list );
AST_LIST_TRAVERSE_SAFE_BEGIN ( & thread_list , x , list ) {
2006-10-04 19:51:38 +00:00
if (( void * ) x -> id == id ) {
2006-04-12 20:40:46 +00:00
AST_LIST_REMOVE_CURRENT ( & thread_list , list );
break ;
}
}
AST_LIST_TRAVERSE_SAFE_END ;
AST_LIST_UNLOCK ( & thread_list );
if ( x ) {
free ( x -> name );
free ( x );
}
}
2007-02-14 20:22:20 +00:00
#if !defined(LOW_MEMORY)
/*! \brief Give an overview of core settings */
static int handle_show_settings ( int fd , int argc , char * argv [])
{
char buf [ BUFSIZ ];
struct tm tm ;
ast_cli ( fd , " \n PBX Core settings \n " );
ast_cli ( fd , "----------------- \n " );
2007-02-14 20:45:23 +00:00
ast_cli ( fd , " Version: %s \n " , "" ASTERISK_VERSION "" );
2007-02-14 20:22:20 +00:00
if ( option_maxcalls )
ast_cli ( fd , " Max. calls: %d (Current %d) \n " , option_maxcalls , ast_active_channels ());
else
ast_cli ( fd , " Max. calls: Not set \n " );
if ( option_maxfiles )
ast_cli ( fd , " Max. open file handles: %d \n " , option_maxfiles );
else
ast_cli ( fd , " Max. open file handles: Not set \n " );
ast_cli ( fd , " Verbosity: %d \n " , option_verbose );
ast_cli ( fd , " Debug level: %d \n " , option_debug );
ast_cli ( fd , " Max load avg: %lf \n " , option_maxload );
if ( localtime_r ( & ast_startuptime , & tm )) {
strftime ( buf , sizeof ( buf ), "%H:%M:%S" , & tm );
ast_cli ( fd , " Startup time: %s \n " , buf );
}
if ( localtime_r ( & ast_lastreloadtime , & tm )) {
strftime ( buf , sizeof ( buf ), "%H:%M:%S" , & tm );
ast_cli ( fd , " Last reload time: %s \n " , buf );
}
ast_cli ( fd , " System: %s/%s built by %s on %s %s \n " , ast_build_os , ast_build_kernel , ast_build_user , ast_build_machine , ast_build_date );
ast_cli ( fd , " System name: %s \n " , ast_config_AST_SYSTEM_NAME );
ast_cli ( fd , " Default language: %s \n " , defaultlanguage );
ast_cli ( fd , " Language prefix: %s \n " , ast_language_is_prefix ? "Enabled" : "Disabled" );
ast_cli ( fd , " User name and group: %s/%s \n " , ast_config_AST_RUN_USER , ast_config_AST_RUN_GROUP );
ast_cli ( fd , " Executable includes: %s \n " , ast_test_flag ( & ast_options , AST_OPT_FLAG_EXEC_INCLUDES ) ? "Enabled" : "Disabled" );
ast_cli ( fd , " Transcode via SLIN: %s \n " , ast_test_flag ( & ast_options , AST_OPT_FLAG_TRANSCODE_VIA_SLIN ) ? "Enabled" : "Disabled" );
ast_cli ( fd , " Internal timing: %s \n " , ast_test_flag ( & ast_options , AST_OPT_FLAG_INTERNAL_TIMING ) ? "Enabled" : "Disabled" );
ast_cli ( fd , " Transmit silence during rec: %s \n " , ast_test_flag ( & ast_options , AST_OPT_FLAG_INTERNAL_TIMING ) ? "Enabled" : "Disabled" );
ast_cli ( fd , " \n * Subsystems \n " );
ast_cli ( fd , " ------------- \n " );
ast_cli ( fd , " Manager (AMI): %s \n " , check_manager_enabled () ? "Enabled" : "Disabled" );
ast_cli ( fd , " Web Manager (AMI/HTTP): %s \n " , check_webmanager_enabled () ? "Enabled" : "Disabled" );
ast_cli ( fd , " Call data records: %s \n " , check_cdr_enabled () ? "Enabled" : "Disabled" );
ast_cli ( fd , " Realtime Architecture (ARA): %s \n " , ast_realtime_enabled () ? "Enabled" : "Disabled" );
/*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
ast_cli ( fd , " \n * Directories \n " );
ast_cli ( fd , " ------------- \n " );
ast_cli ( fd , " Configuration file: %s \n " , ast_config_AST_CONFIG_FILE );
ast_cli ( fd , " Configuration directory: %s \n " , ast_config_AST_CONFIG_DIR );
ast_cli ( fd , " Module directory: %s \n " , ast_config_AST_MODULE_DIR );
ast_cli ( fd , " Spool directory: %s \n " , ast_config_AST_SPOOL_DIR );
ast_cli ( fd , " Log directory: %s \n " , ast_config_AST_LOG_DIR );
ast_cli ( fd , " \n\n " );
return 0 ;
}
#endif
2006-04-12 20:40:46 +00:00
static int handle_show_threads ( int fd , int argc , char * argv [])
{
int count = 0 ;
struct thread_list_t * cur ;
AST_LIST_LOCK ( & thread_list );
AST_LIST_TRAVERSE ( & thread_list , cur , list ) {
ast_cli ( fd , "%p %s \n " , ( void * ) cur -> id , cur -> name );
count ++ ;
}
AST_LIST_UNLOCK ( & thread_list );
ast_cli ( fd , "%d threads listed. \n " , count );
return 0 ;
}
struct profile_entry {
const char * name ;
uint64_t scale ; /* if non-zero, values are scaled by this */
int64_t mark ;
int64_t value ;
int64_t events ;
};
struct profile_data {
int entries ;
int max_size ;
struct profile_entry e [ 0 ];
};
static struct profile_data * prof_data ;
2006-06-08 18:03:08 +00:00
/*! \brief allocates a counter with a given name and scale.
* \return Returns the identifier of the counter.
2006-04-12 20:40:46 +00:00
*/
int ast_add_profile ( const char * name , uint64_t scale )
{
int l = sizeof ( struct profile_data );
int n = 10 ; /* default entries */
if ( prof_data == NULL ) {
prof_data = ast_calloc ( 1 , l + n * sizeof ( struct profile_entry ));
if ( prof_data == NULL )
return - 1 ;
prof_data -> entries = 0 ;
prof_data -> max_size = n ;
}
if ( prof_data -> entries >= prof_data -> max_size ) {
void * p ;
n = prof_data -> max_size + 20 ;
p = ast_realloc ( prof_data , l + n * sizeof ( struct profile_entry ));
if ( p == NULL )
return - 1 ;
prof_data = p ;
prof_data -> max_size = n ;
}
n = prof_data -> entries ++ ;
prof_data -> e [ n ]. name = ast_strdup ( name );
prof_data -> e [ n ]. value = 0 ;
prof_data -> e [ n ]. events = 0 ;
prof_data -> e [ n ]. mark = 0 ;
prof_data -> e [ n ]. scale = scale ;
return n ;
}
int64_t ast_profile ( int i , int64_t delta )
{
if ( ! prof_data || i < 0 || i > prof_data -> entries ) /* invalid index */
return 0 ;
if ( prof_data -> e [ i ]. scale > 1 )
delta /= prof_data -> e [ i ]. scale ;
prof_data -> e [ i ]. value += delta ;
prof_data -> e [ i ]. events ++ ;
return prof_data -> e [ i ]. value ;
}
#if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
#if defined(__FreeBSD__)
#include <machine/cpufunc.h>
#elif defined(linux)
2006-08-22 05:34:44 +00:00
static __inline uint64_t
2006-04-12 20:40:46 +00:00
rdtsc ( void )
{
uint64_t rv ;
__asm __volatile ( ".byte 0x0f, 0x31" : "=A" ( rv ));
return ( rv );
}
#endif
#else /* supply a dummy function on other platforms */
2006-08-22 05:34:44 +00:00
static __inline uint64_t
2006-04-12 20:40:46 +00:00
rdtsc ( void )
{
return 0 ;
}
#endif
int64_t ast_mark ( int i , int startstop )
{
if ( ! prof_data || i < 0 || i > prof_data -> entries ) /* invalid index */
return 0 ;
if ( startstop == 1 )
prof_data -> e [ i ]. mark = rdtsc ();
else {
prof_data -> e [ i ]. mark = ( rdtsc () - prof_data -> e [ i ]. mark );
if ( prof_data -> e [ i ]. scale > 1 )
prof_data -> e [ i ]. mark /= prof_data -> e [ i ]. scale ;
prof_data -> e [ i ]. value += prof_data -> e [ i ]. mark ;
prof_data -> e [ i ]. events ++ ;
}
return prof_data -> e [ i ]. mark ;
}
2006-09-18 19:54:18 +00:00
static int handle_show_profile ( int fd , int argc , char * argv [])
{
int i , min , max ;
char * search = NULL ;
if ( prof_data == NULL )
return 0 ;
min = 0 ;
max = prof_data -> entries ;
2006-11-07 23:14:04 +00:00
if ( argc > 3 ) { /* specific entries */
if ( isdigit ( argv [ 3 ][ 0 ])) {
min = atoi ( argv [ 3 ]);
if ( argc == 5 && strcmp ( argv [ 4 ], "-" ))
max = atoi ( argv [ 4 ]);
2006-09-18 19:54:18 +00:00
} else
2006-11-07 23:14:04 +00:00
search = argv [ 3 ];
2006-09-18 19:54:18 +00:00
}
if ( max > prof_data -> entries )
max = prof_data -> entries ;
if ( ! strcmp ( argv [ 1 ], "clear" )) {
for ( i = min ; i < max ; i ++ ) {
if ( ! search || strstr ( prof_data -> e [ i ]. name , search )) {
prof_data -> e [ i ]. value = 0 ;
prof_data -> e [ i ]. events = 0 ;
}
}
return 0 ;
}
ast_cli ( fd , "profile values (%d, allocated %d) \n ------------------- \n " ,
prof_data -> entries , prof_data -> max_size );
ast_cli ( fd , "%6s %8s %10s %12s %12s %s \n " , "ID" , "Scale" , "Events" ,
"Value" , "Average" , "Name" );
for ( i = min ; i < max ; i ++ ) {
struct profile_entry * e = & prof_data -> e [ i ];
if ( ! search || strstr ( prof_data -> e [ i ]. name , search ))
ast_cli ( fd , "%6d: [%8ld] %10ld %12lld %12lld %s \n " ,
i ,
( long ) e -> scale ,
( long ) e -> events , ( long long ) e -> value ,
( long long )( e -> events ? e -> value / e -> events : e -> value ),
e -> name );
}
return 0 ;
}
2006-12-06 07:23:32 +00:00
static const char show_version_files_help [] =
2006-11-02 23:16:09 +00:00
"Usage: core show file version [like <pattern>] \n "
2006-09-18 19:54:18 +00:00
" Lists the revision numbers of the files used to build this copy of Asterisk. \n "
2005-06-06 20:27:51 +00:00
" Optional regular expression pattern is used to filter the file list. \n " ;
2006-06-08 18:03:08 +00:00
/*! \brief CLI command to list module versions */
2005-06-06 20:27:51 +00:00
static int handle_show_version_files ( int fd , int argc , char * argv [])
{
2005-07-25 22:19:13 +00:00
#define FORMAT "%-25.25s %-40.40s\n"
2005-06-06 20:27:51 +00:00
struct file_version * iterator ;
2005-06-06 21:09:59 +00:00
regex_t regexbuf ;
int havepattern = 0 ;
2005-06-06 22:39:32 +00:00
int havename = 0 ;
2005-08-22 18:45:41 +00:00
int count_files = 0 ;
2005-06-06 21:09:59 +00:00
switch ( argc ) {
case 5 :
if ( ! strcasecmp ( argv [ 3 ], "like" )) {
if ( regcomp ( & regexbuf , argv [ 4 ], REG_EXTENDED | REG_NOSUB ))
return RESULT_SHOWUSAGE ;
havepattern = 1 ;
} else
return RESULT_SHOWUSAGE ;
break ;
2005-06-06 22:39:32 +00:00
case 4 :
havename = 1 ;
break ;
2005-06-06 21:09:59 +00:00
case 3 :
break ;
default :
return RESULT_SHOWUSAGE ;
}
2005-06-06 20:27:51 +00:00
2005-06-06 21:09:59 +00:00
ast_cli ( fd , FORMAT , "File" , "Revision" );
ast_cli ( fd , FORMAT , "----" , "--------" );
2005-06-06 20:27:51 +00:00
AST_LIST_LOCK ( & file_versions );
AST_LIST_TRAVERSE ( & file_versions , iterator , list ) {
2005-06-06 22:39:32 +00:00
if ( havename && strcasecmp ( iterator -> file , argv [ 3 ]))
continue ;
2005-06-06 21:09:59 +00:00
if ( havepattern && regexec ( & regexbuf , iterator -> file , 0 , NULL , 0 ))
continue ;
ast_cli ( fd , FORMAT , iterator -> file , iterator -> version );
2005-08-22 18:45:41 +00:00
count_files ++ ;
2005-06-06 22:39:32 +00:00
if ( havename )
break ;
2005-06-06 20:27:51 +00:00
}
AST_LIST_UNLOCK ( & file_versions );
2005-08-22 18:45:41 +00:00
if ( ! havename ) {
ast_cli ( fd , "%d files listed. \n " , count_files );
}
2005-06-06 21:09:59 +00:00
if ( havepattern )
regfree ( & regexbuf );
2005-06-06 20:27:51 +00:00
return RESULT_SUCCESS ;
2005-06-06 21:09:59 +00:00
#undef FORMAT
2005-06-06 20:27:51 +00:00
}
2006-01-18 22:17:31 +00:00
static char * complete_show_version_files ( const char * line , const char * word , int pos , int state )
2005-06-06 20:27:51 +00:00
{
struct file_version * find ;
int which = 0 ;
char * ret = NULL ;
int matchlen = strlen ( word );
if ( pos != 3 )
return NULL ;
AST_LIST_LOCK ( & file_versions );
AST_LIST_TRAVERSE ( & file_versions , find , list ) {
2006-04-14 22:17:27 +00:00
if ( ! strncasecmp ( word , find -> file , matchlen ) && ++ which > state ) {
ret = ast_strdup ( find -> file );
break ;
2005-06-06 20:27:51 +00:00
}
}
AST_LIST_UNLOCK ( & file_versions );
return ret ;
}
2005-06-07 16:07:06 +00:00
#endif /* ! LOW_MEMORY */
2005-06-06 20:27:51 +00:00
2003-08-07 03:48:00 +00:00
int ast_register_atexit ( void ( * func )( void ))
{
int res = - 1 ;
struct ast_atexit * ae ;
2006-02-14 22:28:01 +00:00
ast_unregister_atexit ( func );
2006-01-24 20:27:09 +00:00
AST_LIST_LOCK ( & atexits );
2006-02-14 22:28:01 +00:00
if (( ae = ast_calloc ( 1 , sizeof ( * ae )))) {
2006-01-24 20:27:09 +00:00
AST_LIST_INSERT_HEAD ( & atexits , ae , list );
2003-08-07 03:48:00 +00:00
ae -> func = func ;
res = 0 ;
}
2006-01-24 20:27:09 +00:00
AST_LIST_UNLOCK ( & atexits );
2003-08-07 03:48:00 +00:00
return res ;
}
void ast_unregister_atexit ( void ( * func )( void ))
{
2006-01-24 20:27:09 +00:00
struct ast_atexit * ae ;
AST_LIST_LOCK ( & atexits );
AST_LIST_TRAVERSE_SAFE_BEGIN ( & atexits , ae , list ) {
2003-08-07 03:48:00 +00:00
if ( ae -> func == func ) {
2006-01-24 20:27:09 +00:00
AST_LIST_REMOVE_CURRENT ( & atexits , list );
2003-08-07 03:48:00 +00:00
break ;
}
}
2006-01-24 20:27:09 +00:00
AST_LIST_TRAVERSE_SAFE_END
AST_LIST_UNLOCK ( & atexits );
2003-08-07 03:48:00 +00:00
}
2003-03-16 22:37:31 +00:00
static int fdprint ( int fd , const char * s )
2001-05-09 03:11:22 +00:00
{
return write ( fd , s , strlen ( s ) + 1 );
}
2006-06-08 18:03:08 +00:00
/*! \brief NULL handler so we can collect the child exit status */
2004-08-22 18:33:19 +00:00
static void null_sig_handler ( int signal )
{
}
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
2006-05-25 18:31:19 +00:00
* a child process */
2005-09-14 22:40:54 +00:00
static unsigned int safe_system_level = 0 ;
static void * safe_system_prev_handler ;
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 */
if ( level == 0 )
safe_system_prev_handler = signal ( SIGCHLD , null_sig_handler );
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 */
if ( level == 0 )
signal ( SIGCHLD , safe_system_prev_handler );
ast_mutex_unlock ( & safe_system_lock );
}
int ast_safe_system ( const char * s )
{
pid_t pid ;
2006-10-18 21:05:52 +00:00
#ifdef HAVE_WORKING_FORK
2006-05-25 18:31:19 +00:00
int x ;
2006-10-18 21:05:52 +00:00
#endif
2006-05-25 18:31:19 +00:00
int res ;
struct rusage rusage ;
int status ;
2006-09-16 23:53:58 +00:00
#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
ast_replace_sigchld ();
2005-09-14 22:40:54 +00:00
2006-09-18 19:58:27 +00:00
#ifdef HAVE_WORKING_FORK
2004-03-21 18:15:37 +00:00
pid = fork ();
2006-09-18 19:58:27 +00:00
#else
pid = vfork ();
2006-09-16 23:53:58 +00:00
#endif
2005-09-14 22:40:54 +00:00
2004-03-21 18:15:37 +00:00
if ( pid == 0 ) {
2006-10-18 21:05:52 +00:00
#ifdef HAVE_WORKING_FORK
2006-05-01 21:48:30 +00:00
if ( ast_opt_high_priority )
ast_set_priority ( 0 );
2004-03-21 18:15:37 +00:00
/* Close file descriptors and launch system command */
2005-09-14 22:40:54 +00:00
for ( x = STDERR_FILENO + 1 ; x < 4096 ; x ++ )
2004-03-21 18:15:37 +00:00
close ( x );
2006-10-18 21:05:52 +00:00
#endif
2006-06-09 20:26:25 +00:00
execl ( "/bin/sh" , "/bin/sh" , "-c" , s , ( char * ) NULL );
2006-10-27 17:42:57 +00:00
_exit ( 1 );
2004-03-21 18:15:37 +00:00
} else if ( pid > 0 ) {
2007-01-23 00:11:32 +00:00
for (;;) {
2004-03-21 18:15:37 +00:00
res = wait4 ( pid , & status , 0 , & rusage );
if ( res > - 1 ) {
2005-09-14 22:40:54 +00:00
res = WIFEXITED ( status ) ? WEXITSTATUS ( status ) : - 1 ;
break ;
} else if ( errno != EINTR )
2004-06-21 19:12:20 +00:00
break ;
2004-03-21 18:15:37 +00:00
}
} else {
ast_log ( LOG_WARNING , "Fork failed: %s \n " , strerror ( errno ));
res = - 1 ;
}
2005-09-14 22:40:54 +00:00
2006-05-25 18:31:19 +00:00
ast_unreplace_sigchld ();
2006-08-21 20:12:18 +00:00
#else
res = - 1 ;
#endif
2005-09-14 22:40:54 +00:00
2004-03-21 18:15:37 +00:00
return res ;
}
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
*/
2006-05-26 21:47:52 +00:00
void ast_console_toggle_mute ( int fd ) {
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 ;
2006-05-26 19:48:17 +00:00
ast_cli ( fd , "Console is not muted anymore. \n " );
} else {
2006-05-26 21:47:52 +00:00
consoles [ x ]. mute = 1 ;
2006-05-26 19:48:17 +00:00
ast_cli ( fd , "Console is muted. \n " );
}
return ;
}
}
ast_cli ( fd , "Couldn't find remote console. \n " );
}
/*!
2006-06-08 18:03:08 +00:00
* \brief log the string to all attached console clients
2006-05-26 19:48:17 +00:00
*/
static void ast_network_puts_mutable ( const char * string )
{
int x ;
2006-05-26 21:47:52 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
2006-05-26 19:48:17 +00:00
if ( consoles [ x ]. mute )
2006-05-26 21:47:52 +00:00
continue ;
2006-05-26 19:48:17 +00:00
if ( consoles [ x ]. fd > - 1 )
fdprint ( consoles [ x ]. p [ 1 ], string );
}
}
/*!
2006-06-08 18:03:08 +00:00
* \brief log the string to the console, and all attached
2006-05-26 19:48:17 +00:00
* console clients
*/
void ast_console_puts_mutable ( const char * string )
{
fputs ( string , stdout );
fflush ( stdout );
ast_network_puts_mutable ( string );
}
2005-10-24 20:12:06 +00:00
/*!
2006-06-08 18:03:08 +00:00
* \brief write the string to all attached console clients
2004-01-12 05:05:35 +00:00
*/
static void ast_network_puts ( const char * string )
{
2004-06-29 04:42:19 +00:00
int x ;
2006-03-31 00:33:28 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
2004-06-29 04:42:19 +00:00
if ( consoles [ x ]. fd > - 1 )
fdprint ( consoles [ x ]. p [ 1 ], string );
}
2004-01-12 05:05:35 +00:00
}
2005-10-24 20:12:06 +00:00
/*!
2004-01-12 05:05:35 +00:00
* write the string to the console, and all attached
* console clients
*/
void ast_console_puts ( const char * string )
{
2004-06-29 04:42:19 +00:00
fputs ( string , stdout );
fflush ( stdout );
ast_network_puts ( string );
2004-01-12 05:05:35 +00:00
}
2006-08-08 06:32:04 +00:00
static void network_verboser ( const char * s )
{
ast_network_puts_mutable ( s );
2001-05-09 03:11:22 +00:00
}
static pthread_t lthread ;
static void * netconsole ( void * vconsole )
{
struct console * con = vconsole ;
2006-03-31 00:33:28 +00:00
char hostname [ MAXHOSTNAMELEN ] = "" ;
2001-05-09 03:11:22 +00:00
char tmp [ 512 ];
int res ;
2004-04-25 20:42:45 +00:00
struct pollfd fds [ 2 ];
2001-05-09 03:11:22 +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 ));
2006-05-08 12:32:44 +00:00
snprintf ( tmp , sizeof ( tmp ), "%s/%ld/%s \n " , hostname , ( long ) ast_mainpid , ASTERISK_VERSION );
2001-05-09 03:11:22 +00:00
fdprint ( con -> fd , tmp );
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
res = 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 ) {
2001-05-09 03:11:22 +00:00
res = read ( con -> fd , tmp , sizeof ( tmp ));
2001-10-11 18:51:39 +00:00
if ( res < 1 ) {
2001-05-09 03:11:22 +00:00
break ;
2001-10-11 18:51:39 +00:00
}
2001-05-09 03:11:22 +00:00
tmp [ res ] = 0 ;
ast_cli_command ( con -> fd , tmp );
}
2004-04-25 20:42:45 +00:00
if ( fds [ 1 ]. revents ) {
2001-05-09 03:11:22 +00:00
res = read ( con -> p [ 0 ], tmp , sizeof ( tmp ));
if ( res < 1 ) {
ast_log ( LOG_ERROR , "read returned %d \n " , res );
break ;
}
res = write ( con -> fd , tmp , res );
if ( res < 1 )
break ;
}
}
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 "Remote UNIX connection disconnected \n " );
close ( con -> fd );
close ( con -> p [ 0 ]);
close ( con -> p [ 1 ]);
con -> fd = - 1 ;
return NULL ;
}
static void * listener ( void * unused )
{
2004-12-14 23:36:30 +00:00
struct sockaddr_un sunaddr ;
2001-05-09 03:11:22 +00:00
int s ;
2005-05-15 03:21:51 +00:00
socklen_t len ;
2001-05-09 03:11:22 +00:00
int x ;
2001-10-11 18:51:39 +00:00
int flags ;
2004-04-25 20:42:45 +00:00
struct pollfd fds [ 1 ];
2001-05-09 03:11:22 +00:00
pthread_attr_t attr ;
pthread_attr_init ( & attr );
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED );
2006-03-31 00:33:28 +00:00
for (;;) {
2002-09-12 03:22:07 +00:00
if ( ast_socket < 0 )
return NULL ;
2004-04-25 20:42:45 +00:00
fds [ 0 ]. fd = ast_socket ;
2006-03-31 00:33:28 +00:00
fds [ 0 ]. events = POLLIN ;
2004-04-25 20:42:45 +00:00
s = poll ( fds , 1 , - 1 );
2006-07-03 05:14:06 +00:00
pthread_testcancel ();
2003-09-29 20:20:04 +00:00
if ( s < 0 ) {
2004-03-04 21:32:32 +00:00
if ( errno != EINTR )
2004-04-25 20:42:45 +00:00
ast_log ( LOG_WARNING , "poll returned error: %s \n " , strerror ( errno ));
2003-09-29 20:20:04 +00:00
continue ;
}
2004-12-14 23:36:30 +00:00
len = sizeof ( sunaddr );
s = accept ( ast_socket , ( struct sockaddr * ) & sunaddr , & len );
2001-05-09 03:11:22 +00:00
if ( s < 0 ) {
2004-03-02 16:58:17 +00:00
if ( errno != EINTR )
2004-03-03 00:05:00 +00:00
ast_log ( LOG_WARNING , "Accept returned %d: %s \n " , s , strerror ( errno ));
2001-05-09 03:11:22 +00:00
} else {
2006-03-31 00:33:28 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ ) {
2001-05-09 03:11:22 +00:00
if ( consoles [ x ]. fd < 0 ) {
2001-10-11 18:51:39 +00:00
if ( socketpair ( AF_LOCAL , SOCK_STREAM , 0 , consoles [ x ]. p )) {
2001-05-09 03:11:22 +00:00
ast_log ( LOG_ERROR , "Unable to create pipe: %s \n " , strerror ( errno ));
consoles [ x ]. fd = - 1 ;
fdprint ( s , "Server failed to create pipe \n " );
close ( s );
break ;
}
2001-10-11 18:51:39 +00:00
flags = fcntl ( consoles [ x ]. p [ 1 ], F_GETFL );
fcntl ( consoles [ x ]. p [ 1 ], F_SETFL , flags | O_NONBLOCK );
2001-05-09 03:11:22 +00:00
consoles [ x ]. fd = s ;
2006-05-26 21:47:52 +00:00
consoles [ x ]. mute = ast_opt_mute ;
2006-10-04 19:51:38 +00:00
if ( ast_pthread_create_background ( & consoles [ x ]. t , & attr , netconsole , & consoles [ x ])) {
2004-05-07 14:08:50 +00:00
ast_log ( LOG_ERROR , "Unable to spawn thread to handle connection: %s \n " , strerror ( errno ));
2006-04-11 21:58:44 +00:00
close ( consoles [ x ]. p [ 0 ]);
close ( consoles [ x ]. p [ 1 ]);
2001-05-09 03:11:22 +00:00
consoles [ x ]. fd = - 1 ;
fdprint ( s , "Server failed to spawn thread \n " );
close ( s );
}
break ;
}
}
if ( x >= AST_MAX_CONNECTS ) {
fdprint ( s , "No more connections allowed \n " );
ast_log ( LOG_WARNING , "No more connections allowed \n " );
close ( s );
} else if ( consoles [ x ]. fd > - 1 ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 "Remote UNIX connection \n " );
}
}
}
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
2005-07-25 23:09:13 +00:00
for ( x = 0 ; x < AST_MAX_CONNECTS ; x ++ )
2001-05-09 03:11:22 +00:00
consoles [ x ]. fd = - 1 ;
2005-07-25 23:09:13 +00:00
unlink ( ast_config_AST_SOCKET );
2001-05-09 03:11:22 +00:00
ast_socket = socket ( PF_LOCAL , SOCK_STREAM , 0 );
if ( ast_socket < 0 ) {
ast_log ( LOG_WARNING , "Unable to create control socket: %s \n " , strerror ( errno ));
return - 1 ;
}
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 ;
}
ast_register_verbose ( network_verboser );
2006-10-04 19:51:38 +00:00
ast_pthread_create_background ( & lthread , NULL , listener , NULL );
2005-02-11 21:16:34 +00:00
2005-07-25 23:09:13 +00:00
if ( ! ast_strlen_zero ( ast_config_AST_CTL_OWNER )) {
2005-02-11 21:16:34 +00:00
struct passwd * pw ;
2006-10-29 20:47:01 +00:00
if (( pw = getpwnam ( ast_config_AST_CTL_OWNER )) == NULL )
2005-07-25 23:09:13 +00:00
ast_log ( LOG_WARNING , "Unable to find uid of user %s \n " , ast_config_AST_CTL_OWNER );
2006-10-29 20:47:01 +00:00
else
2005-07-25 23:09:13 +00:00
uid = pw -> pw_uid ;
2005-02-11 21:16:34 +00:00
}
2005-07-25 23:09:13 +00:00
if ( ! ast_strlen_zero ( ast_config_AST_CTL_GROUP )) {
2005-02-11 21:16:34 +00:00
struct group * grp ;
2006-10-29 20:47:01 +00:00
if (( grp = getgrnam ( ast_config_AST_CTL_GROUP )) == NULL )
2005-07-25 23:09:13 +00:00
ast_log ( LOG_WARNING , "Unable to find gid of group %s \n " , ast_config_AST_CTL_GROUP );
2006-10-29 20:47:01 +00:00
else
2005-07-25 23:09:13 +00:00
gid = grp -> gr_gid ;
2005-02-11 21:16:34 +00:00
}
2005-07-25 23:09:13 +00:00
if ( chown ( ast_config_AST_SOCKET , uid , gid ) < 0 )
ast_log ( LOG_WARNING , "Unable to change ownership of %s: %s \n " , ast_config_AST_SOCKET , strerror ( errno ));
if ( ! ast_strlen_zero ( ast_config_AST_CTL_PERMISSIONS )) {
2005-12-26 18:35:28 +00:00
int p1 ;
2005-02-11 21:16:34 +00:00
mode_t p ;
2005-12-26 18:35:28 +00:00
sscanf ( ast_config_AST_CTL_PERMISSIONS , "%o" , & p1 );
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 ) {
ast_log ( LOG_WARNING , "Unable to create socket: %s \n " , strerror ( errno ));
return 0 ;
}
2004-12-14 23:36:30 +00:00
memset ( & sunaddr , 0 , sizeof ( sunaddr ));
sunaddr . sun_family = AF_LOCAL ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( sunaddr . sun_path , ( char * ) 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
2005-10-24 20:12:06 +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
*/
1999-11-15 04:57:28 +00:00
static void urg_handler ( int num )
{
2000-01-02 20:59:00 +00:00
signal ( num , urg_handler );
1999-11-15 04:57:28 +00:00
return ;
}
2001-05-09 03:11:22 +00:00
static void hup_handler ( int num )
{
if ( option_verbose > 1 )
2003-12-01 02:47:19 +00:00
printf ( "Received HUP signal -- Reloading configs \n " );
2004-02-23 03:43:21 +00:00
if ( restartnow )
execvp ( _argv [ 0 ], _argv );
2007-01-30 17:23:56 +00:00
need_reload = 1 ;
2005-07-15 22:12:55 +00:00
signal ( num , hup_handler );
2001-05-09 03:11:22 +00:00
}
2003-09-16 19:35:57 +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 */
2003-09-16 19:35:57 +00:00
int n , status ;
/*
* Reap all dead children -- not just one
*/
for ( n = 0 ; wait4 ( - 1 , & status , WNOHANG , NULL ) > 0 ; n ++ )
;
if ( n == 0 && option_debug )
2003-12-01 02:47:19 +00:00
printf ( "Huh? Child handler, but nobody there? \n " );
2005-07-15 22:12:55 +00:00
signal ( sig , child_handler );
2001-05-09 03:11:22 +00:00
}
2003-09-16 19:35:57 +00:00
2006-11-22 17:41:07 +00:00
/*! \brief Set maximum open files */
static void set_ulimit ( int value )
{
struct rlimit l = { 0 , 0 };
if ( value <= 0 ) {
ast_log ( LOG_WARNING , "Unable to change max files open to invalid value %i \n " , value );
return ;
}
l . rlim_cur = value ;
l . rlim_max = value ;
if ( setrlimit ( RLIMIT_NOFILE , & l )) {
ast_log ( LOG_WARNING , "Unable to disable core size resource limit: %s \n " , strerror ( errno ));
return ;
}
ast_log ( LOG_NOTICE , "Setting max files open to %d \n " , value );
return ;
}
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 );
}
2006-06-08 18:03:08 +00:00
/*! \brief We set ourselves to a high priority, that we might pre-empt everything
2005-10-24 20:12:06 +00:00
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__
1999-12-19 22:38:55 +00:00
if ( pri ) {
2001-03-22 04:14:04 +00:00
sched . sched_priority = 10 ;
if ( sched_setscheduler ( 0 , SCHED_RR , & sched )) {
1999-12-19 22:38:55 +00:00
ast_log ( LOG_WARNING , "Unable to set high priority \n " );
return - 1 ;
2001-03-22 04:14:04 +00:00
} else
if ( option_verbose )
ast_verbose ( "Set to realtime thread \n " );
1999-12-19 22:38:55 +00:00
} else {
sched . sched_priority = 0 ;
if ( sched_setscheduler ( 0 , SCHED_OTHER , & sched )) {
ast_log ( LOG_WARNING , "Unable to set normal priority \n " );
return - 1 ;
}
}
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
if ( option_verbose )
ast_verbose ( "Set to high priority \n " );
} else {
if ( setpriority ( PRIO_PROCESS , 0 , 0 ) == - 1 ) {
ast_log ( LOG_WARNING , "Unable to set normal priority \n " );
return - 1 ;
}
}
#endif
1999-12-19 22:38:55 +00:00
return 0 ;
}
2003-08-07 03:48:00 +00:00
static void ast_run_atexits ( void )
{
struct ast_atexit * ae ;
2006-01-24 20:27:09 +00:00
AST_LIST_LOCK ( & atexits );
AST_LIST_TRAVERSE ( & atexits , ae , list ) {
2003-08-07 03:48:00 +00:00
if ( ae -> func )
ae -> func ();
}
2006-01-24 20:27:09 +00:00
AST_LIST_UNLOCK ( & atexits );
2003-08-07 03:48:00 +00:00
}
2002-05-14 14:43:52 +00:00
static void quit_handler ( int num , int nice , int safeshutdown , int restart )
1999-11-15 04:57:28 +00:00
{
1999-12-19 22:38:55 +00:00
char filename [ 80 ] = "" ;
2002-05-14 14:43:52 +00:00
time_t s , e ;
int x ;
2005-06-03 01:42:31 +00:00
/* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
ast_cdr_engine_term ();
2002-05-14 14:43:52 +00:00
if ( safeshutdown ) {
shuttingdown = 1 ;
if ( ! nice ) {
/* Begin shutdown routine, hanging up active channels */
ast_begin_shutdown ( 1 );
2005-12-04 20:40:46 +00:00
if ( option_verbose && ast_opt_console )
2002-05-14 14:43:52 +00:00
ast_verbose ( "Beginning asterisk %s.... \n " , restart ? "restart" : "shutdown" );
time ( & s );
2006-03-31 00:33:28 +00:00
for (;;) {
2002-05-14 14:43:52 +00:00
time ( & e );
/* Wait up to 15 seconds for all channels to go away */
if (( e - s ) > 15 )
break ;
if ( ! ast_active_channels ())
break ;
if ( ! shuttingdown )
break ;
/* Sleep 1/10 of a second */
usleep ( 100000 );
}
} else {
if ( nice < 2 )
ast_begin_shutdown ( 0 );
2005-12-04 20:40:46 +00:00
if ( option_verbose && ast_opt_console )
2002-05-14 14:43:52 +00:00
ast_verbose ( "Waiting for inactivity to perform %s... \n " , restart ? "restart" : "halt" );
2006-03-31 00:33:28 +00:00
for (;;) {
2002-05-14 14:43:52 +00:00
if ( ! ast_active_channels ())
break ;
if ( ! shuttingdown )
break ;
sleep ( 1 );
}
}
if ( ! shuttingdown ) {
2005-12-04 20:40:46 +00:00
if ( option_verbose && ast_opt_console )
2002-05-14 14:43:52 +00:00
ast_verbose ( "Asterisk %s cancelled. \n " , restart ? "restart" : "shutdown" );
return ;
}
}
2005-12-04 20:40:46 +00:00
if ( ast_opt_console || ast_opt_remote ) {
2001-05-09 03:11:22 +00:00
if ( getenv ( "HOME" ))
snprintf ( filename , sizeof ( filename ), "%s/.asterisk_history" , getenv ( "HOME" ));
2004-05-04 14:54:42 +00:00
if ( ! ast_strlen_zero ( filename ))
2003-02-06 06:15:25 +00:00
ast_el_write_history ( filename );
if ( el != NULL )
el_end ( el );
if ( el_hist != NULL )
history_end ( el_hist );
2001-05-09 03:11:22 +00:00
}
2003-08-07 03:48:00 +00:00
if ( option_verbose )
ast_verbose ( "Executing last minute cleanups \n " );
ast_run_atexits ();
1999-11-15 04:57:28 +00:00
/* Called on exit */
2005-12-04 20:40:46 +00:00
if ( option_verbose && ast_opt_console )
2002-05-14 14:43:52 +00:00
ast_verbose ( "Asterisk %s ending (%d). \n " , ast_active_channels () ? "uncleanly" : "cleanly" , num );
2006-09-19 16:23:45 +00:00
if ( option_debug )
1999-11-15 04:57:28 +00:00
ast_log ( LOG_DEBUG , "Asterisk ending (%d). \n " , num );
2003-02-20 06:00:14 +00:00
manager_event ( EVENT_FLAG_SYSTEM , "Shutdown" , "Shutdown: %s \r\n Restart: %s \r\n " , ast_active_channels () ? "Uncleanly" : "Cleanly" , restart ? "True" : "False" );
2002-09-12 03:22:07 +00:00
if ( ast_socket > - 1 ) {
2006-07-03 05:14:06 +00:00
pthread_cancel ( lthread );
2001-05-09 03:11:22 +00:00
close ( ast_socket );
2002-09-12 03:22:07 +00:00
ast_socket = - 1 ;
2006-03-25 23:22:44 +00:00
unlink ( ast_config_AST_SOCKET );
2002-09-12 03:22:07 +00:00
}
2001-05-09 03:11:22 +00:00
if ( ast_consock > - 1 )
close ( ast_consock );
2005-12-04 20:40:46 +00:00
if ( ! ast_opt_remote )
unlink ( ast_config_AST_PID );
2002-05-14 14:43:52 +00:00
printf ( term_quit ());
if ( restart ) {
2005-12-04 20:40:46 +00:00
if ( option_verbose || ast_opt_console )
2002-05-14 14:43:52 +00:00
ast_verbose ( "Preparing for Asterisk restart... \n " );
/* Mark all FD's for closing on exec */
2006-03-31 00:33:28 +00:00
for ( x = 3 ; x < 32768 ; x ++ ) {
2002-05-14 14:43:52 +00:00
fcntl ( x , F_SETFD , FD_CLOEXEC );
}
2005-12-04 20:40:46 +00:00
if ( option_verbose || ast_opt_console )
2007-02-16 17:26:20 +00:00
ast_verbose ( "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 ();
2004-02-23 03:43:21 +00:00
/* If there is a consolethread running send it a SIGHUP
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 );
2004-06-17 01:13:10 +00:00
} else {
/* close logger */
close_logger ();
2003-08-07 03:48:00 +00:00
}
exit ( 0 );
2002-05-14 14:43:52 +00:00
}
static void __quit_handler ( int num )
{
quit_handler ( num , 0 , 1 , 0 );
1999-11-15 04:57:28 +00:00
}
2003-06-27 23:02:52 +00:00
static const char * fix_header ( char * outbuf , int maxout , const char * s , char * cmp )
2002-05-14 14:43:52 +00:00
{
2003-06-27 23:02:52 +00:00
const char * c ;
if ( ! strncmp ( s , cmp , strlen ( cmp ))) {
c = s + strlen ( cmp );
2002-05-14 14:43:52 +00:00
term_color ( outbuf , cmp , COLOR_GRAY , 0 , maxout );
2003-06-27 23:02:52 +00:00
return c ;
2002-05-14 14:43:52 +00:00
}
2003-06-27 23:02:52 +00:00
return NULL ;
2002-05-14 14:43:52 +00:00
}
2006-08-08 06:32:04 +00:00
static void console_verboser ( const char * s )
1999-12-19 22:38:55 +00:00
{
2002-05-14 14:43:52 +00:00
char tmp [ 80 ];
2006-03-31 00:33:28 +00:00
const char * c = NULL ;
2006-08-08 06:32:04 +00:00
if (( c = fix_header ( tmp , sizeof ( tmp ), s , VERBOSE_PREFIX_4 )) ||
( c = fix_header ( tmp , sizeof ( tmp ), s , VERBOSE_PREFIX_3 )) ||
( c = fix_header ( tmp , sizeof ( tmp ), s , VERBOSE_PREFIX_2 )) ||
( c = fix_header ( tmp , sizeof ( tmp ), s , VERBOSE_PREFIX_1 ))) {
fputs ( tmp , stdout );
fputs ( c , stdout );
} else
fputs ( s , stdout );
2000-01-02 20:59:00 +00:00
fflush ( stdout );
2006-08-08 06:32:04 +00:00
/* Wake up a poll()ing console */
if ( ast_opt_console && consolethread != AST_PTHREADT_NULL )
pthread_kill ( consolethread , SIGURG );
1999-12-19 22:38:55 +00:00
}
2004-08-01 18:12:52 +00:00
static int ast_all_zeros ( char * s )
{
2006-03-31 00:33:28 +00:00
while ( * s ) {
2004-08-01 18:12:52 +00:00
if ( * s > 32 )
return 0 ;
s ++ ;
}
return 1 ;
}
1999-12-19 22:38:55 +00:00
static void consolehandler ( char * s )
{
2002-05-14 14:43:52 +00:00
printf ( term_end ());
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" );
} else
1999-12-19 22:38:55 +00:00
ast_cli_command ( STDOUT_FILENO , s );
}
2003-02-06 06:15:25 +00:00
static int remoteconsolehandler ( char * s )
2001-05-09 03:11:22 +00:00
{
2003-02-06 06:15:25 +00:00
int ret = 0 ;
2006-07-12 14:04:16 +00:00
2001-05-09 03:11:22 +00:00
/* Called when readline data is available */
2006-07-12 14:04:16 +00:00
if ( ! ast_all_zeros ( s ))
2003-02-06 06:15:25 +00:00
ast_el_add_history ( s );
2006-07-12 14:04:16 +00:00
/* The real handler for bang */
if ( s [ 0 ] == '!' ) {
if ( s [ 1 ])
ast_safe_system ( s + 1 );
else
ast_safe_system ( getenv ( "SHELL" ) ? getenv ( "SHELL" ) : "/bin/sh" );
ret = 1 ;
}
if (( strncasecmp ( s , "quit" , 4 ) == 0 || strncasecmp ( s , "exit" , 4 ) == 0 ) &&
( s [ 4 ] == '\0' || isspace ( s [ 4 ]))) {
quit_handler ( 0 , 0 , 0 , 0 );
ret = 1 ;
}
2003-02-06 06:15:25 +00:00
return ret ;
2001-05-09 03:11:22 +00:00
}
2006-12-06 07:23:32 +00:00
static const char abort_halt_help [] =
2002-05-14 14:43:52 +00:00
"Usage: abort shutdown \n "
" Causes Asterisk to abort an executing shutdown or restart, and resume normal \n "
" call operations. \n " ;
2006-12-06 07:23:32 +00:00
static const char shutdown_now_help [] =
2003-02-06 06:15:25 +00:00
"Usage: stop now \n "
2002-05-14 14:43:52 +00:00
" Shuts down a running Asterisk immediately, hanging up all active calls . \n " ;
2006-12-06 07:23:32 +00:00
static const char shutdown_gracefully_help [] =
2003-02-06 06:15:25 +00:00
"Usage: stop gracefully \n "
2002-05-14 14:43:52 +00:00
" Causes Asterisk to not accept new calls, and exit when all \n "
" active calls have terminated normally. \n " ;
2006-12-06 07:23:32 +00:00
static const char shutdown_when_convenient_help [] =
2003-04-23 16:24:09 +00:00
"Usage: stop when convenient \n "
" Causes Asterisk to perform a shutdown when all active calls have ended. \n " ;
2006-12-06 07:23:32 +00:00
static const char restart_now_help [] =
2002-05-14 14:43:52 +00:00
"Usage: restart now \n "
2004-12-28 07:51:25 +00:00
" Causes Asterisk to hangup all calls and exec() itself performing a cold \n "
2002-05-14 14:43:52 +00:00
" restart. \n " ;
2006-12-06 07:23:32 +00:00
static const char restart_gracefully_help [] =
2002-05-14 14:43:52 +00:00
"Usage: restart gracefully \n "
2004-12-28 07:51:25 +00:00
" Causes Asterisk to stop accepting new calls and exec() itself performing a cold \n "
2002-05-14 14:43:52 +00:00
" restart when all active calls have ended. \n " ;
2006-12-06 07:23:32 +00:00
static const char restart_when_convenient_help [] =
2002-05-14 14:43:52 +00:00
"Usage: restart when convenient \n "
" Causes Asterisk to perform a cold restart when all active calls have ended. \n " ;
2001-05-09 03:11:22 +00:00
2006-12-06 07:23:32 +00:00
static const char bang_help [] =
2003-10-22 03:46:36 +00:00
"Usage: !<command> \n "
" Executes a given shell command \n " ;
2006-12-06 07:23:32 +00:00
static const char show_warranty_help [] =
2006-11-02 23:16:09 +00:00
"Usage: core show warranty \n "
2007-02-13 06:10:11 +00:00
" Shows the warranty (if any) for this copy of Asterisk. \n " ;
2005-12-23 03:04:38 +00:00
2006-12-06 07:23:32 +00:00
static const char show_license_help [] =
2006-11-02 23:16:09 +00:00
"Usage: core show license \n "
2007-02-13 06:10:11 +00:00
" Shows the license(s) for this copy of Asterisk. \n " ;
2005-12-23 03:04:38 +00:00
2006-12-06 07:23:32 +00:00
static const char version_help [] =
2006-11-02 23:16:09 +00:00
"Usage: core show version \n "
2006-04-29 00:15:28 +00:00
" Shows Asterisk version information. \n " ;
static int handle_version ( int fd , int argc , char * argv [])
{
2006-11-09 06:35:05 +00:00
if ( argc != 3 )
2006-04-29 00:15:28 +00:00
return RESULT_SHOWUSAGE ;
ast_cli ( fd , "Asterisk %s built by %s @ %s on a %s running %s on %s \n " ,
ASTERISK_VERSION , ast_build_user , ast_build_hostname ,
ast_build_machine , ast_build_os , ast_build_date );
return RESULT_SUCCESS ;
}
2003-03-16 22:37:31 +00:00
#if 0
1999-12-19 22:38:55 +00:00
static int handle_quit(int fd, int argc, char *argv[])
{
if (argc != 1)
return RESULT_SHOWUSAGE;
2002-05-14 14:43:52 +00:00
quit_handler(0, 0, 1, 0);
return RESULT_SUCCESS;
}
2003-03-16 22:37:31 +00:00
#endif
2002-05-14 14:43:52 +00:00
static int handle_shutdown_now ( int fd , int argc , char * argv [])
{
if ( argc != 2 )
return RESULT_SHOWUSAGE ;
quit_handler ( 0 , 0 /* Not nice */ , 1 /* safely */ , 0 /* not restart */ );
return RESULT_SUCCESS ;
}
static int handle_shutdown_gracefully ( int fd , int argc , char * argv [])
{
if ( argc != 2 )
return RESULT_SHOWUSAGE ;
quit_handler ( 0 , 1 /* nicely */ , 1 /* safely */ , 0 /* no restart */ );
return RESULT_SUCCESS ;
}
2003-04-23 16:24:09 +00:00
static int handle_shutdown_when_convenient ( int fd , int argc , char * argv [])
{
if ( argc != 3 )
return RESULT_SHOWUSAGE ;
2006-01-13 06:49:23 +00:00
ast_cli ( fd , "Waiting for inactivity to perform halt \n " );
2003-04-23 16:24:09 +00:00
quit_handler ( 0 , 2 /* really nicely */ , 1 /* safely */ , 0 /* don't restart */ );
return RESULT_SUCCESS ;
}
2002-05-14 14:43:52 +00:00
static int handle_restart_now ( int fd , int argc , char * argv [])
{
if ( argc != 2 )
return RESULT_SHOWUSAGE ;
quit_handler ( 0 , 0 /* not nicely */ , 1 /* safely */ , 1 /* restart */ );
return RESULT_SUCCESS ;
}
static int handle_restart_gracefully ( int fd , int argc , char * argv [])
{
if ( argc != 2 )
return RESULT_SHOWUSAGE ;
quit_handler ( 0 , 1 /* nicely */ , 1 /* safely */ , 1 /* restart */ );
return RESULT_SUCCESS ;
}
static int handle_restart_when_convenient ( int fd , int argc , char * argv [])
{
if ( argc != 3 )
return RESULT_SHOWUSAGE ;
2006-01-13 06:49:23 +00:00
ast_cli ( fd , "Waiting for inactivity to perform restart \n " );
2002-05-14 14:43:52 +00:00
quit_handler ( 0 , 2 /* really nicely */ , 1 /* safely */ , 1 /* restart */ );
return RESULT_SUCCESS ;
}
static int handle_abort_halt ( int fd , int argc , char * argv [])
{
if ( argc != 2 )
return RESULT_SHOWUSAGE ;
ast_cancel_shutdown ();
shuttingdown = 0 ;
1999-12-19 22:38:55 +00:00
return RESULT_SUCCESS ;
}
2003-10-22 03:46:36 +00:00
static int handle_bang ( int fd , int argc , char * argv [])
{
return RESULT_SUCCESS ;
}
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
};
static int show_warranty ( int fd , int argc , char * argv [])
{
2007-02-13 05:57:52 +00:00
ast_cli ( fd , warranty_lines );
2005-12-23 03:04:38 +00:00
return RESULT_SUCCESS ;
}
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
};
static int show_license ( int fd , int argc , char * argv [])
{
2007-02-13 05:57:52 +00:00
ast_cli ( fd , license_lines );
2005-12-23 03:04:38 +00:00
return RESULT_SUCCESS ;
}
2003-10-22 03:46:36 +00:00
1999-12-19 22:38:55 +00:00
#define ASTERISK_PROMPT "*CLI> "
2001-05-09 03:11:22 +00:00
#define ASTERISK_PROMPT2 "%s*CLI> "
2006-09-18 19:54:18 +00:00
static struct ast_cli_entry cli_asterisk [] = {
{ { "abort" , "halt" , NULL },
handle_abort_halt , "Cancel a running halt" ,
abort_halt_help },
{ { "stop" , "now" , NULL },
handle_shutdown_now , "Shut down Asterisk immediately" ,
shutdown_now_help },
{ { "stop" , "gracefully" , NULL },
handle_shutdown_gracefully , "Gracefully shut down Asterisk" ,
shutdown_gracefully_help },
{ { "stop" , "when" , "convenient" , NULL },
handle_shutdown_when_convenient , "Shut down Asterisk at empty call volume" ,
shutdown_when_convenient_help },
{ { "restart" , "now" , NULL },
handle_restart_now , "Restart Asterisk immediately" , restart_now_help },
{ { "restart" , "gracefully" , NULL },
handle_restart_gracefully , "Restart Asterisk gracefully" ,
restart_gracefully_help },
{ { "restart" , "when" , "convenient" , NULL },
handle_restart_when_convenient , "Restart Asterisk at empty call volume" ,
restart_when_convenient_help },
2006-11-02 23:16:09 +00:00
{ { "core" , "show" , "warranty" , NULL },
2006-09-18 19:54:18 +00:00
show_warranty , "Show the warranty (if any) for this copy of Asterisk" ,
show_warranty_help },
2006-11-02 23:16:09 +00:00
{ { "core" , "show" , "license" , NULL },
2006-09-18 19:54:18 +00:00
show_license , "Show the license(s) for this copy of Asterisk" ,
show_license_help },
2006-11-02 23:16:09 +00:00
{ { "core" , "show" , "version" , NULL },
2006-09-18 19:54:18 +00:00
handle_version , "Display version info" ,
version_help },
{ { "!" , NULL },
handle_bang , "Execute a shell command" ,
bang_help },
#if !defined(LOW_MEMORY)
2006-11-02 23:16:09 +00:00
{ { "core" , "show" , "file" , "version" , NULL },
2006-09-18 19:54:18 +00:00
handle_show_version_files , "List versions of files used to build Asterisk" ,
2006-09-21 21:17:39 +00:00
show_version_files_help , complete_show_version_files },
2006-09-18 19:54:18 +00:00
2006-11-02 23:16:09 +00:00
{ { "core" , "show" , "threads" , NULL },
2006-09-18 19:54:18 +00:00
handle_show_threads , "Show running threads" ,
show_threads_help },
2006-11-02 23:16:09 +00:00
{ { "core" , "show" , "profile" , NULL },
2006-09-18 19:54:18 +00:00
handle_show_profile , "Display profiling info" ,
2006-09-21 21:17:39 +00:00
NULL },
2006-09-18 19:54:18 +00:00
2007-02-14 20:22:20 +00:00
{ { "core" , "show" , "settings" , NULL },
handle_show_settings , "Show some core settings" ,
NULL },
2006-11-02 23:16:09 +00:00
{ { "core" , "clear" , "profile" , NULL },
2006-09-18 19:54:18 +00:00
handle_show_profile , "Clear profiling info" ,
2006-09-21 21:17:39 +00:00
NULL },
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
2003-02-06 06:15:25 +00:00
static int ast_el_read_char ( EditLine * el , char * cp )
{
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 ;
char buf [ 512 ];
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
}
2004-04-25 20:42:45 +00:00
res = poll ( fds , max , - 1 );
2003-02-06 06:15:25 +00:00
if ( res < 0 ) {
if ( errno == EINTR )
continue ;
2004-04-25 20:42:45 +00:00
ast_log ( LOG_ERROR , "poll failed: %s \n " , strerror ( errno ));
2003-02-06 06:15:25 +00:00
break ;
}
2005-12-04 20:40:46 +00:00
if ( ! ast_opt_exec && fds [ 1 ]. revents ) {
2003-02-06 06:15:25 +00:00
num_read = read ( STDIN_FILENO , cp , 1 );
if ( num_read < 1 ) {
break ;
} else
return ( num_read );
}
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 ) {
2004-06-25 14:39:38 +00:00
quit_handler ( 0 , 0 , 0 , 0 );
} else {
int tries ;
2004-06-25 21:14:03 +00:00
int reconnects_per_second = 20 ;
fprintf ( stderr , "Attempting to reconnect for 30 seconds \n " );
2006-03-31 00:33:28 +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 );
2004-06-25 14:39:38 +00:00
printf ( term_quit ());
2004-06-25 21:14:03 +00:00
WELCOME_MESSAGE ;
2004-06-25 14:39:38 +00:00
break ;
2006-10-29 20:47:01 +00:00
} else
2004-06-25 14:39:38 +00:00
usleep ( 1000000 / reconnects_per_second );
}
2004-12-28 07:51:25 +00:00
if ( tries >= 30 * reconnects_per_second ) {
2004-06-25 14:39:38 +00:00
fprintf ( stderr , "Failed to reconnect for 30 seconds. Quitting. \n " );
quit_handler ( 0 , 0 , 0 , 0 );
}
}
2003-02-06 06:15:25 +00:00
}
buf [ res ] = '\0' ;
2005-12-04 20:40:46 +00:00
if ( ! ast_opt_exec && ! lastpos )
2003-02-06 06:15:25 +00:00
write ( STDOUT_FILENO , " \r " , 1 );
write ( STDOUT_FILENO , buf , res );
2003-12-03 04:55:55 +00:00
if (( buf [ res - 1 ] == '\n' ) || ( buf [ res - 2 ] == '\n' )) {
2003-03-06 06:00:17 +00:00
* cp = CC_REFRESH ;
return ( 1 );
2006-10-29 20:47:01 +00:00
} else
2003-02-06 06:15:25 +00:00
lastpos = 1 ;
}
}
* cp = '\0' ;
return ( 0 );
}
static char * cli_prompt ( EditLine * el )
1999-12-19 22:38:55 +00:00
{
2004-03-26 04:59:41 +00:00
static char prompt [ 200 ];
char * pfmt ;
2006-03-31 00:33:28 +00:00
int color_used = 0 ;
2004-05-02 19:13:16 +00:00
char term_code [ 20 ];
2004-03-26 04:59:41 +00:00
if (( pfmt = getenv ( "ASTERISK_PROMPT" ))) {
char * t = pfmt , * p = prompt ;
memset ( prompt , 0 , sizeof ( prompt ));
while ( * t != '\0' && * p < sizeof ( prompt )) {
if ( * t == '%' ) {
2005-05-08 16:44:25 +00:00
char hostname [ MAXHOSTNAMELEN ] = "" ;
2004-05-02 19:13:16 +00:00
int i ;
2005-12-26 18:35:28 +00:00
time_t ts ;
2004-05-02 19:13:16 +00:00
struct tm tm ;
2004-05-31 16:43:35 +00:00
#ifdef linux
2004-05-02 19:13:16 +00:00
FILE * LOADAVG ;
2004-05-31 16:43:35 +00:00
#endif
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 ++ ;
if ( sscanf ( t , "%d;%d%n" , & fgcolor , & bgcolor , & i ) == 2 ) {
strncat ( p , term_color_code ( term_code , fgcolor , bgcolor , sizeof ( term_code )), sizeof ( prompt ) - strlen ( prompt ) - 1 );
t += i - 1 ;
} else if ( sscanf ( t , "%d%n" , & fgcolor , & i ) == 1 ) {
strncat ( p , term_color_code ( term_code , fgcolor , 0 , sizeof ( term_code )), sizeof ( prompt ) - strlen ( prompt ) - 1 );
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 */
memset ( & tm , 0 , sizeof ( tm ));
time ( & ts );
2006-10-29 20:47:01 +00:00
if ( localtime_r ( & ts , & tm ))
2006-03-31 00:33:28 +00:00
strftime ( p , sizeof ( prompt ) - strlen ( prompt ), "%Y-%m-%d" , & tm );
break ;
case 'h' : /* hostname */
2006-10-29 20:47:01 +00:00
if ( ! gethostname ( hostname , sizeof ( hostname ) - 1 ))
2006-03-31 00:33:28 +00:00
strncat ( p , hostname , sizeof ( prompt ) - strlen ( prompt ) - 1 );
2006-10-29 20:47:01 +00:00
else
2006-03-31 00:33:28 +00:00
strncat ( p , "localhost" , sizeof ( prompt ) - strlen ( prompt ) - 1 );
break ;
case 'H' : /* short hostname */
if ( ! gethostname ( hostname , sizeof ( hostname ) - 1 )) {
for ( i = 0 ; i < sizeof ( hostname ); i ++ ) {
if ( hostname [ i ] == '.' ) {
hostname [ i ] = '\0' ;
break ;
2004-05-02 19:13:16 +00:00
}
}
2006-03-31 00:33:28 +00:00
strncat ( p , hostname , sizeof ( prompt ) - strlen ( prompt ) - 1 );
2006-10-29 20:47:01 +00:00
} else
2006-03-31 00:33:28 +00:00
strncat ( p , "localhost" , sizeof ( prompt ) - strlen ( prompt ) - 1 );
break ;
2004-03-26 04:59:41 +00:00
#ifdef linux
2006-03-31 00:33:28 +00:00
case 'l' : /* load avg */
t ++ ;
if (( LOADAVG = fopen ( "/proc/loadavg" , "r" ))) {
float avg1 , avg2 , avg3 ;
int actproc , totproc , npid , which ;
fscanf ( LOADAVG , "%f %f %f %d/%d %d" ,
& avg1 , & avg2 , & avg3 , & actproc , & totproc , & npid );
if ( sscanf ( t , "%d" , & which ) == 1 ) {
switch ( which ) {
case 1 :
snprintf ( p , sizeof ( prompt ) - strlen ( prompt ), "%.2f" , avg1 );
break ;
case 2 :
snprintf ( p , sizeof ( prompt ) - strlen ( prompt ), "%.2f" , avg2 );
break ;
case 3 :
snprintf ( p , sizeof ( prompt ) - strlen ( prompt ), "%.2f" , avg3 );
break ;
case 4 :
snprintf ( p , sizeof ( prompt ) - strlen ( prompt ), "%d/%d" , actproc , totproc );
break ;
case 5 :
snprintf ( p , sizeof ( prompt ) - strlen ( prompt ), "%d" , npid );
break ;
2004-03-26 04:59:41 +00:00
}
}
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) */
strncat ( p , ast_config_AST_SYSTEM_NAME , sizeof ( prompt ) - strlen ( prompt ) - 1 );
break ;
2006-03-31 00:33:28 +00:00
case 't' : /* time */
memset ( & tm , 0 , sizeof ( tm ));
time ( & ts );
2006-10-29 20:47:01 +00:00
if ( localtime_r ( & ts , & tm ))
2006-03-31 00:33:28 +00:00
strftime ( p , sizeof ( prompt ) - strlen ( prompt ), "%H:%M:%S" , & tm );
break ;
case '#' : /* process console or remote? */
2006-10-29 20:47:01 +00:00
if ( ! ast_opt_remote )
2006-03-31 00:33:28 +00:00
strncat ( p , "#" , sizeof ( prompt ) - strlen ( prompt ) - 1 );
2006-10-29 20:47:01 +00:00
else
2006-03-31 00:33:28 +00:00
strncat ( p , ">" , sizeof ( prompt ) - strlen ( prompt ) - 1 );
break ;
case '%' : /* literal % */
strncat ( p , "%" , sizeof ( prompt ) - strlen ( prompt ) - 1 );
break ;
case '\0' : /* % is last character - prevent bug */
t -- ;
break ;
2004-03-26 04:59:41 +00:00
}
2006-10-29 20:47:01 +00:00
while ( * p != '\0' )
2004-03-26 04:59:41 +00:00
p ++ ;
t ++ ;
} else {
* p = * t ;
p ++ ;
t ++ ;
}
}
2004-05-02 19:13:16 +00:00
if ( color_used ) {
/* Force colors back to normal at end */
term_color_code ( term_code , COLOR_WHITE , COLOR_BLACK , sizeof ( term_code ));
2006-10-29 20:47:01 +00:00
if ( strlen ( term_code ) > sizeof ( prompt ) - strlen ( prompt ))
2004-05-02 19:13:16 +00:00
strncat ( prompt + sizeof ( prompt ) - strlen ( term_code ) - 1 , term_code , strlen ( term_code ));
2006-10-29 20:47:01 +00:00
else
2004-05-02 19:13:16 +00:00
strncat ( p , term_code , sizeof ( term_code ));
}
2004-03-26 04:59:41 +00:00
} else if ( remotehostname )
2003-02-06 06:15:25 +00:00
snprintf ( prompt , sizeof ( prompt ), ASTERISK_PROMPT2 , remotehostname );
else
snprintf ( prompt , sizeof ( prompt ), ASTERISK_PROMPT );
2003-04-08 13:45:36 +00:00
return ( prompt );
2003-02-06 06:15:25 +00:00
}
static char ** ast_el_strtoarr ( char * buf )
{
char ** match_list = NULL , * retstr ;
2004-06-29 04:42:19 +00:00
size_t match_list_len ;
2003-02-06 06:15:25 +00:00
int matches = 0 ;
2004-06-29 04:42:19 +00:00
match_list_len = 1 ;
2003-02-06 06:15:25 +00:00
while ( ( retstr = strsep ( & buf , " " )) != NULL ) {
2004-04-06 07:42:01 +00:00
if ( ! strcmp ( retstr , AST_CLI_COMPLETE_EOF ))
break ;
2004-06-29 04:42:19 +00:00
if ( matches + 1 >= match_list_len ) {
match_list_len <<= 1 ;
2006-02-14 22:28:01 +00:00
if ( ! ( match_list = ast_realloc ( match_list , match_list_len * sizeof ( char * )))) {
/* TODO: Handle memory allocation failure */
}
2003-02-06 06:15:25 +00:00
}
2004-04-07 18:26:24 +00:00
match_list [ matches ++ ] = strdup ( retstr );
2003-02-06 06:15:25 +00:00
}
2004-06-29 04:42:19 +00:00
if ( ! match_list )
return ( char ** ) NULL ;
2003-02-06 06:15:25 +00:00
2006-02-14 22:28:01 +00:00
if ( matches >= match_list_len ) {
if ( ! ( match_list = ast_realloc ( match_list , ( match_list_len + 1 ) * sizeof ( char * )))) {
/* TODO: Handle memory allocation failure */
}
}
2003-02-06 06:15:25 +00:00
match_list [ matches ] = ( char * ) NULL ;
return match_list ;
}
static int ast_el_sort_compare ( const void * i1 , const void * i2 )
{
char * s1 , * s2 ;
s1 = (( char ** ) i1 )[ 0 ];
s2 = (( char ** ) i2 )[ 0 ];
return strcasecmp ( s1 , s2 );
}
static int ast_cli_display_match_list ( char ** matches , int len , int max )
{
int i , idx , limit , count ;
int screenwidth = 0 ;
int numoutput = 0 , numoutputline = 0 ;
screenwidth = ast_get_termcols ( STDOUT_FILENO );
/* find out how many entries can be put on one line, with two spaces between strings */
limit = screenwidth / ( max + 2 );
if ( limit == 0 )
limit = 1 ;
/* how many lines of output */
count = len / limit ;
if ( count * limit < len )
count ++ ;
idx = 1 ;
2006-01-07 15:17:10 +00:00
qsort ( & matches [ 0 ], ( size_t )( len ), sizeof ( char * ), ast_el_sort_compare );
2003-02-06 06:15:25 +00:00
for (; count > 0 ; count -- ) {
numoutputline = 0 ;
for ( i = 0 ; i < limit && matches [ idx ]; i ++ , idx ++ ) {
/* Don't print dupes */
if ( ( matches [ idx + 1 ] != NULL && strcmp ( matches [ idx ], matches [ idx + 1 ]) == 0 ) ) {
i -- ;
2004-07-16 20:41:17 +00:00
free ( matches [ idx ]);
matches [ idx ] = NULL ;
2003-02-06 06:15:25 +00:00
continue ;
}
2004-10-01 18:35:35 +00:00
numoutput ++ ;
numoutputline ++ ;
2003-02-06 06:15:25 +00:00
fprintf ( stdout , "%-*s " , max , matches [ idx ]);
2004-07-16 20:41:17 +00:00
free ( matches [ idx ]);
matches [ idx ] = NULL ;
2003-02-06 06:15:25 +00:00
}
if ( numoutputline > 0 )
fprintf ( stdout , " \n " );
}
return numoutput ;
1999-12-19 22:38:55 +00:00
}
2003-02-06 06:15:25 +00:00
static char * cli_complete ( EditLine * el , int ch )
2001-05-09 03:11:22 +00:00
{
2006-03-31 00:33:28 +00:00
int len = 0 ;
2003-02-06 06:15:25 +00:00
char * ptr ;
int nummatches = 0 ;
char ** matches ;
int retval = CC_ERROR ;
2004-03-24 08:09:01 +00:00
char buf [ 2048 ];
2001-05-09 03:11:22 +00:00
int res ;
2003-02-06 06:15:25 +00:00
LineInfo * lf = ( LineInfo * ) el_line ( el );
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 ) {
2003-02-06 06:15:25 +00:00
snprintf ( buf , sizeof ( buf ), "_COMMAND NUMMATCHES \" %s \" \" %s \" " , lf -> buffer , ptr );
fdprint ( ast_consock , buf );
res = read ( ast_consock , buf , sizeof ( buf ));
buf [ res ] = '\0' ;
nummatches = atoi ( buf );
if ( nummatches > 0 ) {
2004-04-06 07:42:01 +00:00
char * mbuf ;
int mlen = 0 , maxmbuf = 2048 ;
2006-02-14 22:28:01 +00:00
/* Start with a 2048 byte buffer */
if ( ! ( mbuf = ast_malloc ( maxmbuf )))
2004-04-07 18:26:24 +00:00
return ( char * )( CC_ERROR );
2003-02-06 06:15:25 +00:00
snprintf ( buf , sizeof ( buf ), "_COMMAND MATCHESARRAY \" %s \" \" %s \" " , lf -> buffer , ptr );
fdprint ( ast_consock , buf );
2004-04-06 07:42:01 +00:00
res = 0 ;
2004-04-09 17:46:04 +00:00
mbuf [ 0 ] = '\0' ;
2004-04-06 07:42:01 +00:00
while ( ! strstr ( mbuf , AST_CLI_COMPLETE_EOF ) && res != - 1 ) {
if ( mlen + 1024 > maxmbuf ) {
/* Every step increment buffer 1024 bytes */
2006-02-14 22:28:01 +00:00
maxmbuf += 1024 ;
if ( ! ( mbuf = ast_realloc ( mbuf , maxmbuf )))
2004-04-07 18:26:24 +00:00
return ( char * )( CC_ERROR );
2004-04-06 07:42:01 +00:00
}
/* Only read 1024 bytes at a time */
res = read ( ast_consock , mbuf + mlen , 1024 );
if ( res > 0 )
mlen += res ;
}
mbuf [ mlen ] = '\0' ;
2003-02-06 06:15:25 +00:00
2004-04-06 07:42:01 +00:00
matches = ast_el_strtoarr ( mbuf );
free ( mbuf );
2003-02-06 06:15:25 +00:00
} else
matches = ( char ** ) NULL ;
2004-10-01 18:35:35 +00:00
} else {
2006-01-07 15:17:10 +00:00
char ** p , * oldbuf = NULL ;
nummatches = 0 ;
2003-02-06 06:15:25 +00:00
matches = ast_cli_completion_matches (( char * ) lf -> buffer , ptr );
2006-01-07 15:17:10 +00:00
for ( p = matches ; p && * p ; p ++ ) {
if ( ! oldbuf || strcmp ( * p , oldbuf ))
nummatches ++ ;
oldbuf = * p ;
}
2003-02-06 06:15:25 +00:00
}
if ( matches ) {
int i ;
int matches_num , maxlen , match_len ;
if ( matches [ 0 ][ 0 ] != '\0' ) {
el_deletestr ( el , ( int ) len );
el_insertstr ( el , matches [ 0 ]);
retval = CC_REFRESH ;
}
if ( nummatches == 1 ) {
/* Found an exact match */
2003-04-08 13:45:36 +00:00
el_insertstr ( el , " " );
2003-02-06 06:15:25 +00:00
retval = CC_REFRESH ;
} else {
/* Must be more than one match */
for ( i = 1 , maxlen = 0 ; matches [ i ]; i ++ ) {
match_len = strlen ( matches [ i ]);
if ( match_len > maxlen )
maxlen = match_len ;
}
matches_num = i - 1 ;
if ( matches_num > 1 ) {
fprintf ( stdout , " \n " );
ast_cli_display_match_list ( matches , nummatches , maxlen );
retval = CC_REDISPLAY ;
} else {
2003-04-08 13:45:36 +00:00
el_insertstr ( el , " " );
2003-02-06 06:15:25 +00:00
retval = CC_REFRESH ;
}
}
2007-01-19 17:02:36 +00:00
for ( i = 0 ; matches [ i ]; i ++ )
free ( matches [ i ]);
2005-12-27 17:24:54 +00:00
free ( matches );
2003-02-06 06:15:25 +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 ;
2004-07-31 02:23:27 +00:00
char * editor = getenv ( "AST_EDITOR" );
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 );
el_set ( el , EL_EDITMODE , 1 );
2004-07-30 18:30:48 +00:00
el_set ( el , EL_EDITOR , editor ? editor : "emacs" );
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 );
2003-02-06 06:15:25 +00:00
return 0 ;
}
static int ast_el_add_history ( char * buf )
{
HistEvent ev ;
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
2004-01-23 19:12:44 +00:00
if ( strlen ( buf ) > 256 )
return 0 ;
2003-02-06 06:15:25 +00:00
return ( history ( el_hist , & ev , H_ENTER , buf ));
}
static int ast_el_write_history ( char * filename )
{
HistEvent ev ;
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
return ( history ( el_hist , & ev , H_SAVE , filename ));
}
static int ast_el_read_history ( char * filename )
{
char buf [ 256 ];
FILE * f ;
int ret = - 1 ;
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
if (( f = fopen ( filename , "r" )) == NULL )
return ret ;
while ( ! feof ( f )) {
fgets ( buf , sizeof ( buf ), f );
if ( ! strcmp ( buf , "_HiStOrY_V2_ \n " ))
continue ;
2004-08-03 06:31:20 +00:00
if ( ast_all_zeros ( buf ))
continue ;
2003-02-06 06:15:25 +00:00
if (( ret = ast_el_add_history ( buf )) == - 1 )
break ;
}
fclose ( f );
return ret ;
2001-05-09 03:11:22 +00:00
}
static void ast_remotecontrol ( char * data )
{
char buf [ 80 ];
int res ;
char filename [ 80 ] = "" ;
char * hostname ;
char * cpid ;
char * version ;
int pid ;
char tmp [ 80 ];
2006-03-31 00:33:28 +00:00
char * stringp = NULL ;
2003-02-06 06:15:25 +00:00
char * ebuf ;
int num = 0 ;
2001-05-09 03:11:22 +00:00
read ( ast_consock , buf , sizeof ( buf ));
2003-02-06 06:15:25 +00:00
if ( data )
write ( ast_consock , data , strlen ( data ) + 1 );
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 ;
2006-11-04 18:11:18 +00:00
snprintf ( tmp , sizeof ( tmp ), "core set verbose atleast %d" , option_verbose );
2001-05-09 03:11:22 +00:00
fdprint ( ast_consock , tmp );
2006-11-04 18:11:18 +00:00
snprintf ( tmp , sizeof ( tmp ), "core set debug atleast %d" , option_debug );
2004-09-13 18:19:15 +00:00
fdprint ( ast_consock , tmp );
2006-05-26 21:47:52 +00:00
if ( ast_opt_mute ) {
snprintf ( tmp , sizeof ( tmp ), "log and verbose output currently muted ('logger unmute' to unmute)" );
2006-05-26 19:48:17 +00:00
fdprint ( ast_consock , tmp );
}
2001-05-09 03:11:22 +00:00
ast_verbose ( "Connected to Asterisk %s currently running on %s (pid = %d) \n " , version , hostname , pid );
2003-02-06 06:15:25 +00:00
remotehostname = hostname ;
2001-05-09 03:11:22 +00:00
if ( getenv ( "HOME" ))
snprintf ( filename , sizeof ( filename ), "%s/.asterisk_history" , getenv ( "HOME" ));
2003-02-06 06:15:25 +00:00
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
el_set ( el , EL_GETCFN , ast_el_read_char );
2004-05-04 14:54:42 +00:00
if ( ! ast_strlen_zero ( filename ))
2003-02-06 06:15:25 +00:00
ast_el_read_history ( filename );
2005-12-04 20:40:46 +00:00
if ( ast_opt_exec && data ) { /* hack to print output then exit if asterisk -rx is used */
2003-06-23 16:40:12 +00:00
char tempchar ;
2006-06-13 03:56:09 +00:00
struct pollfd fds ;
fds . fd = ast_consock ;
fds . events = POLLIN ;
fds . revents = 0 ;
while ( poll ( & fds , 1 , 100 ) > 0 )
2004-08-07 14:22:09 +00:00
ast_el_read_char ( el , & tempchar );
2003-06-23 16:40:12 +00:00
return ;
}
2006-03-31 00:33:28 +00:00
for (;;) {
2003-02-06 06:15:25 +00:00
ebuf = ( char * ) el_gets ( el , & num );
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 ;
}
}
}
2007-01-30 17:23:56 +00:00
if ( need_reload ) {
need_reload = 0 ;
ast_module_reload ( NULL );
}
2001-05-09 03:11:22 +00:00
}
printf ( " \n Disconnected from Asterisk server \n " );
}
2004-07-18 17:58:05 +00:00
static int show_version ( void )
{
printf ( "Asterisk " ASTERISK_VERSION " \n " );
return 0 ;
}
2003-02-06 06:15:25 +00:00
static int show_cli_help ( void ) {
2006-03-31 00:33:28 +00:00
printf ( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others. \n " );
2002-09-12 03:22:07 +00:00
printf ( "Usage: asterisk [OPTIONS] \n " );
printf ( "Valid Options: \n " );
2004-07-18 17:58:05 +00:00
printf ( " -V Display version number and exit \n " );
2004-05-13 19:57:45 +00:00
printf ( " -C <configfile> Use an alternate configuration file \n " );
2004-07-18 16:20:54 +00:00
printf ( " -G <group> Run as a group other than the caller \n " );
printf ( " -U <user> Run as a user other than the caller \n " );
2004-05-13 19:57:45 +00:00
printf ( " -c Provide console CLI \n " );
printf ( " -d Enable extra debugging \n " );
2006-08-21 20:12:18 +00:00
#if HAVE_WORKING_FORK
2004-05-13 19:57:45 +00:00
printf ( " -f Do not fork \n " );
2006-08-21 20:12:18 +00:00
printf ( " -F Always fork \n " );
#endif
2004-05-13 19:57:45 +00:00
printf ( " -g Dump core in case of a crash \n " );
printf ( " -h This help screen \n " );
2004-12-28 07:51:25 +00:00
printf ( " -i Initialize crypto keys at startup \n " );
2006-03-31 00:33:28 +00:00
printf ( " -I Enable internal timing if Zaptel timer is available \n " );
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 " );
2006-05-26 19:48:17 +00:00
printf ( " -m Mute the console from debugging and verbose output \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 " );
2004-06-25 14:39:38 +00:00
printf ( " -R Connect to Asterisk, and attempt to reconnect if disconnected \n " );
2004-12-28 07:51:25 +00:00
printf ( " -t Record soundfiles in /var/tmp and move them where they belong after they are done. \n " );
2005-03-11 07:24:10 +00:00
printf ( " -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI. \n " );
2004-05-13 19:57:45 +00:00
printf ( " -v Increase verbosity (multiple v's = more verbose) \n " );
printf ( " -x <cmd> Execute command <cmd> (only valid with -r) \n " );
2002-09-12 03:22:07 +00:00
printf ( " \n " );
return 0 ;
}
2006-03-25 23:50:09 +00:00
static void ast_readconfig ( void )
{
2003-02-06 06:15:25 +00:00
struct ast_config * cfg ;
struct ast_variable * v ;
2005-06-06 03:04:58 +00:00
char * config = AST_CONFIG_FILE ;
2003-02-06 06:15:25 +00:00
2005-12-04 20:40:46 +00:00
if ( ast_opt_override_config ) {
2005-07-25 23:09:13 +00:00
cfg = ast_config_load ( ast_config_AST_CONFIG_FILE );
2004-08-28 17:12:01 +00:00
if ( ! cfg )
2005-07-25 23:09:13 +00:00
ast_log ( LOG_WARNING , "Unable to open specified master config file '%s', using built-in defaults \n " , ast_config_AST_CONFIG_FILE );
2006-10-29 20:47:01 +00:00
} else
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( config );
2003-02-06 06:15:25 +00:00
/* init with buildtime config */
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_CONFIG_DIR , AST_CONFIG_DIR , sizeof ( ast_config_AST_CONFIG_DIR ));
ast_copy_string ( ast_config_AST_SPOOL_DIR , AST_SPOOL_DIR , sizeof ( ast_config_AST_SPOOL_DIR ));
2006-03-30 22:47:11 +00:00
ast_copy_string ( ast_config_AST_MODULE_DIR , AST_MODULE_DIR , sizeof ( ast_config_AST_MODULE_DIR ));
2005-07-25 23:09:13 +00:00
snprintf ( ast_config_AST_MONITOR_DIR , sizeof ( ast_config_AST_MONITOR_DIR ) - 1 , "%s/monitor" , ast_config_AST_SPOOL_DIR );
ast_copy_string ( ast_config_AST_VAR_DIR , AST_VAR_DIR , sizeof ( ast_config_AST_VAR_DIR ));
2006-04-15 22:53:53 +00:00
ast_copy_string ( ast_config_AST_DATA_DIR , AST_DATA_DIR , sizeof ( ast_config_AST_DATA_DIR ));
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_LOG_DIR , AST_LOG_DIR , sizeof ( ast_config_AST_LOG_DIR ));
ast_copy_string ( ast_config_AST_AGI_DIR , AST_AGI_DIR , sizeof ( ast_config_AST_AGI_DIR ));
ast_copy_string ( ast_config_AST_DB , AST_DB , sizeof ( ast_config_AST_DB ));
ast_copy_string ( ast_config_AST_KEY_DIR , AST_KEY_DIR , sizeof ( ast_config_AST_KEY_DIR ));
ast_copy_string ( ast_config_AST_PID , AST_PID , sizeof ( ast_config_AST_PID ));
ast_copy_string ( ast_config_AST_SOCKET , AST_SOCKET , sizeof ( ast_config_AST_SOCKET ));
ast_copy_string ( ast_config_AST_RUN_DIR , AST_RUN_DIR , sizeof ( ast_config_AST_RUN_DIR ));
2003-02-06 06:15:25 +00:00
/* no asterisk.conf? no problem, use buildtime config! */
if ( ! cfg ) {
2004-09-07 14:36:56 +00:00
return ;
2003-02-06 06:15:25 +00:00
}
2006-05-30 21:37:11 +00:00
for ( v = ast_variable_browse ( cfg , "files" ); v ; v = v -> next ) {
2006-10-29 20:47:01 +00:00
if ( ! strcasecmp ( v -> name , "astctlpermissions" ))
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_CTL_PERMISSIONS , v -> value , sizeof ( ast_config_AST_CTL_PERMISSIONS ));
2006-10-29 20:47:01 +00:00
else if ( ! strcasecmp ( v -> name , "astctlowner" ))
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_CTL_OWNER , v -> value , sizeof ( ast_config_AST_CTL_OWNER ));
2006-10-29 20:47:01 +00:00
else if ( ! strcasecmp ( v -> name , "astctlgroup" ))
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_CTL_GROUP , v -> value , sizeof ( ast_config_AST_CTL_GROUP ));
2006-10-29 20:47:01 +00:00
else if ( ! strcasecmp ( v -> name , "astctl" ))
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_CTL , v -> value , sizeof ( ast_config_AST_CTL ));
2005-02-11 21:16:34 +00:00
}
2006-05-30 21:37:11 +00:00
for ( v = ast_variable_browse ( cfg , "directories" ); v ; v = v -> next ) {
2003-02-06 06:15:25 +00:00
if ( ! strcasecmp ( v -> name , "astetcdir" )) {
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_CONFIG_DIR , v -> value , sizeof ( ast_config_AST_CONFIG_DIR ));
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astspooldir" )) {
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_SPOOL_DIR , v -> value , sizeof ( ast_config_AST_SPOOL_DIR ));
snprintf ( ast_config_AST_MONITOR_DIR , sizeof ( ast_config_AST_MONITOR_DIR ) - 1 , "%s/monitor" , v -> value );
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astvarlibdir" )) {
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_VAR_DIR , v -> value , sizeof ( ast_config_AST_VAR_DIR ));
2006-02-28 19:32:39 +00:00
snprintf ( ast_config_AST_DB , sizeof ( ast_config_AST_DB ), "%s/astdb" , v -> value );
2006-04-15 22:53:53 +00:00
} else if ( ! strcasecmp ( v -> name , "astdatadir" )) {
ast_copy_string ( ast_config_AST_DATA_DIR , v -> value , sizeof ( ast_config_AST_DATA_DIR ));
2006-04-15 23:37:29 +00:00
snprintf ( ast_config_AST_KEY_DIR , sizeof ( ast_config_AST_KEY_DIR ), "%s/keys" , v -> value );
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astlogdir" )) {
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_LOG_DIR , v -> value , sizeof ( ast_config_AST_LOG_DIR ));
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astagidir" )) {
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_AGI_DIR , v -> value , sizeof ( ast_config_AST_AGI_DIR ));
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astrundir" )) {
2005-07-25 23:09:13 +00:00
snprintf ( ast_config_AST_PID , sizeof ( ast_config_AST_PID ), "%s/%s" , v -> value , "asterisk.pid" );
snprintf ( ast_config_AST_SOCKET , sizeof ( ast_config_AST_SOCKET ), "%s/%s" , v -> value , ast_config_AST_CTL );
ast_copy_string ( ast_config_AST_RUN_DIR , v -> value , sizeof ( ast_config_AST_RUN_DIR ));
2003-02-06 06:15:25 +00:00
} else if ( ! strcasecmp ( v -> name , "astmoddir" )) {
2005-07-25 23:09:13 +00:00
ast_copy_string ( ast_config_AST_MODULE_DIR , v -> value , sizeof ( ast_config_AST_MODULE_DIR ));
2003-02-06 06:15:25 +00:00
}
}
2006-05-30 21:37:11 +00:00
for ( v = ast_variable_browse ( cfg , "options" ); v ; v = v -> next ) {
2005-02-09 00:13:52 +00:00
/* verbose level (-v at startup) */
2004-10-01 18:35:35 +00:00
if ( ! strcasecmp ( v -> name , "verbose" )) {
2005-07-25 23:09:13 +00:00
option_verbose = atoi ( v -> value );
2006-07-28 19:17:56 +00:00
/* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2005-03-11 07:24:10 +00:00
} else if ( ! strcasecmp ( v -> name , "timestamp" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_TIMESTAMP );
2005-02-09 00:13:52 +00:00
/* whether or not to support #exec in config files */
2005-02-02 03:38:24 +00:00
} else if ( ! strcasecmp ( v -> name , "execincludes" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_EXEC_INCLUDES );
2005-02-09 21:17:34 +00:00
/* debug level (-d at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "debug" )) {
2005-02-09 00:13:52 +00:00
option_debug = 0 ;
if ( sscanf ( v -> value , "%d" , & option_debug ) != 1 ) {
option_debug = ast_true ( v -> value );
}
2006-08-21 20:12:18 +00:00
#if HAVE_WORKING_FORK
2005-02-09 00:13:52 +00:00
/* Disable forking (-f at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "nofork" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_NO_FORK );
2006-04-30 14:55:05 +00:00
/* Always fork, even if verbose or debug are enabled (-F at startup) */
} else if ( ! strcasecmp ( v -> name , "alwaysfork" )) {
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_ALWAYS_FORK );
2006-08-21 20:12:18 +00:00
#endif
2005-02-09 00:13:52 +00:00
/* Run quietly (-q at startup ) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "quiet" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_QUIET );
2005-02-09 00:13:52 +00:00
/* Run as console (-c at startup, implies nofork) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "console" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_CONSOLE );
2006-01-16 17:37:44 +00:00
/* Run with high priority if the O/S permits (-p at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "highpriority" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_HIGH_PRIORITY );
2005-02-09 00:13:52 +00:00
/* Initialize RSA auth keys (IAX2) (-i at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "initcrypto" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_INIT_KEYS );
2005-02-09 00:13:52 +00:00
/* Disable ANSI colors for console (-c at startup) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "nocolor" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_NO_COLOR );
2005-05-19 01:57:19 +00:00
/* Disable some usage warnings for picky people :p */
} else if ( ! strcasecmp ( v -> name , "dontwarn" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_DONT_WARN );
2005-02-09 00:13:52 +00:00
/* Dump core in case of crash (-g) */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "dumpcore" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_DUMP_CORE );
2005-02-09 00:13:52 +00:00
/* Cache recorded sound files to another directory during recording */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "cache_record_files" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_CACHE_RECORD_FILES );
2005-02-09 00:13:52 +00:00
/* Specify cache directory */
2004-09-07 01:49:08 +00:00
} else if ( ! strcasecmp ( v -> name , "record_cache_dir" )) {
2005-07-25 23:09:13 +00:00
ast_copy_string ( record_cache_dir , v -> value , AST_CACHE_DIR_LEN );
2005-04-04 03:28:38 +00:00
/* Build transcode paths via SLINEAR, instead of directly */
} else if ( ! strcasecmp ( v -> name , "transcode_via_sln" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_TRANSCODE_VIA_SLIN );
2005-11-01 17:22:25 +00:00
/* Transmit SLINEAR silence while a channel is being recorded */
} else if ( ! strcasecmp ( v -> name , "transmit_silence_during_record" )) {
2005-12-04 20:40:46 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_TRANSMIT_SILENCE );
2006-03-30 06:07:04 +00:00
/* Enable internal timing */
} else if ( ! strcasecmp ( v -> name , "internal_timing" )) {
2006-03-30 06:26:16 +00:00
ast_set2_flag ( & ast_options , ast_true ( v -> value ), AST_OPT_FLAG_INTERNAL_TIMING );
2005-05-18 01:49:13 +00:00
} else if ( ! strcasecmp ( v -> name , "maxcalls" )) {
2005-07-25 23:09:13 +00:00
if (( sscanf ( v -> value , "%d" , & option_maxcalls ) != 1 ) || ( option_maxcalls < 0 )) {
2005-05-18 01:49:13 +00:00
option_maxcalls = 0 ;
}
2005-10-26 03:58:32 +00:00
} else if ( ! strcasecmp ( v -> name , "maxload" )) {
2005-10-31 21:25:21 +00:00
double test [ 1 ];
if ( getloadavg ( test , 1 ) == - 1 ) {
ast_log ( LOG_ERROR , "Cannot obtain load average on this system. 'maxload' option disabled. \n " );
option_maxload = 0.0 ;
} else if (( sscanf ( v -> value , "%lf" , & option_maxload ) != 1 ) || ( option_maxload < 0.0 )) {
2005-10-26 03:58:32 +00:00
option_maxload = 0.0 ;
}
2006-11-22 17:41:07 +00:00
/* Set the maximum amount of open files */
} else if ( ! strcasecmp ( v -> name , "maxfiles" )) {
2007-02-14 20:22:20 +00:00
option_maxfiles = atoi ( v -> value );
set_ulimit ( option_maxfiles );
2005-11-08 00:30:29 +00:00
/* What user to run as */
} else if ( ! strcasecmp ( v -> name , "runuser" )) {
ast_copy_string ( ast_config_AST_RUN_USER , v -> value , sizeof ( ast_config_AST_RUN_USER ));
/* What group to run as */
} else if ( ! strcasecmp ( v -> name , "rungroup" )) {
ast_copy_string ( ast_config_AST_RUN_GROUP , v -> value , sizeof ( ast_config_AST_RUN_GROUP ));
2006-02-14 23:42:36 +00:00
} else if ( ! strcasecmp ( v -> name , "systemname" )) {
ast_copy_string ( ast_config_AST_SYSTEM_NAME , v -> value , sizeof ( ast_config_AST_SYSTEM_NAME ));
2006-05-30 21:37:11 +00:00
} else if ( ! strcasecmp ( v -> name , "languageprefix" )) {
ast_language_is_prefix = ast_true ( v -> value );
2004-09-07 01:49:08 +00:00
}
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg );
2003-02-06 06:15:25 +00:00
}
1999-11-15 04:57:28 +00:00
int main ( int argc , char * argv [])
{
2004-01-28 21:32:48 +00:00
int c ;
1999-12-19 22:38:55 +00:00
char filename [ 80 ] = "" ;
2006-03-31 00:33:28 +00:00
char hostname [ MAXHOSTNAMELEN ] = "" ;
2002-05-14 14:43:52 +00:00
char tmp [ 80 ];
2001-05-09 03:11:22 +00:00
char * xarg = NULL ;
2002-05-14 14:43:52 +00:00
int x ;
2002-09-12 03:22:07 +00:00
FILE * f ;
2001-05-09 03:11:22 +00:00
sigset_t sigs ;
2003-02-06 06:15:25 +00:00
int num ;
2006-03-31 00:33:28 +00:00
int is_child_of_nonroot = 0 ;
2003-02-06 06:15:25 +00:00
char * buf ;
2006-03-31 00:33:28 +00:00
char * runuser = NULL , * rungroup = NULL ;
2001-05-09 03:11:22 +00:00
2002-05-14 14:43:52 +00:00
/* Remember original args for restart */
if ( argc > sizeof ( _argv ) / sizeof ( _argv [ 0 ]) - 1 ) {
2004-06-13 21:25:10 +00:00
fprintf ( stderr , "Truncating argument size to %d \n " , ( int )( sizeof ( _argv ) / sizeof ( _argv [ 0 ])) - 1 );
2002-05-14 14:43:52 +00:00
argc = sizeof ( _argv ) / sizeof ( _argv [ 0 ]) - 1 ;
}
2006-03-31 00:33:28 +00:00
for ( x = 0 ; x < argc ; x ++ )
2002-05-14 14:43:52 +00:00
_argv [ x ] = argv [ x ];
_argv [ x ] = NULL ;
2004-03-20 07:26:54 +00:00
/* if the progname is rasterisk consider it a remote console */
2004-10-01 18:35:35 +00:00
if ( argv [ 0 ] && ( strstr ( argv [ 0 ], "rasterisk" )) != NULL ) {
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE );
2004-03-20 07:26:54 +00:00
}
2005-05-08 16:44:25 +00:00
if ( gethostname ( hostname , sizeof ( hostname ) - 1 ))
2005-06-05 16:32:16 +00:00
ast_copy_string ( hostname , "<Unknown>" , sizeof ( hostname ));
2004-03-20 21:13:12 +00:00
ast_mainpid = getpid ();
2001-03-22 04:14:04 +00:00
ast_ulaw_init ();
2001-12-25 21:12:07 +00:00
ast_alaw_init ();
2001-03-22 04:14:04 +00:00
callerid_init ();
2006-03-28 22:25:08 +00:00
ast_builtins_init ();
2004-06-25 04:07:52 +00:00
ast_utils_init ();
2001-12-25 21:12:07 +00:00
tdd_init ();
2005-08-23 01:37:26 +00:00
/* When Asterisk restarts after it has dropped the root privileges,
* it can't issue setuid(), setgid(), setgroups() or set_priority()
2006-03-31 00:33:28 +00:00
*/
2005-08-23 01:37:26 +00:00
if ( getenv ( "ASTERISK_ALREADY_NONROOT" ))
is_child_of_nonroot = 1 ;
1999-12-19 22:38:55 +00:00
if ( getenv ( "HOME" ))
snprintf ( filename , sizeof ( filename ), "%s/.asterisk_history" , getenv ( "HOME" ));
1999-11-15 04:57:28 +00:00
/* Check for options */
2007-02-01 19:34:54 +00:00
while (( c = getopt ( argc , argv , "mtThfFdvVqprRgciInx:U:G:C:L:M:" )) != - 1 ) {
2006-03-31 00:33:28 +00:00
switch ( c ) {
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
1999-11-15 04:57:28 +00:00
case 'd' :
option_debug ++ ;
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK );
1999-12-19 22:38:55 +00:00
break ;
2000-01-02 20:59:00 +00:00
case 'c' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE );
2001-03-22 04:14:04 +00:00
break ;
2002-05-14 14:43:52 +00:00
case 'n' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_COLOR );
2002-05-14 14:43:52 +00:00
break ;
2001-05-09 03:11:22 +00:00
case 'r' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE );
2001-05-09 03:11:22 +00:00
break ;
2004-06-25 14:39:38 +00:00
case 'R' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT );
2004-06-25 14:39:38 +00:00
break ;
1999-12-19 22:38:55 +00:00
case 'p' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_HIGH_PRIORITY );
1999-11-15 04:57:28 +00:00
break ;
case 'v' :
option_verbose ++ ;
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_NO_FORK );
1999-11-15 04:57:28 +00:00
break ;
2006-05-26 19:48:17 +00:00
case 'm' :
2006-05-26 21:47:52 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_MUTE );
2006-05-26 19:48:17 +00:00
break ;
2005-05-18 01:49:13 +00:00
case 'M' :
if (( sscanf ( optarg , "%d" , & option_maxcalls ) != 1 ) || ( option_maxcalls < 0 ))
option_maxcalls = 0 ;
break ;
2005-10-26 03:58:32 +00:00
case 'L' :
if (( sscanf ( optarg , "%lf" , & option_maxload ) != 1 ) || ( option_maxload < 0.0 ))
option_maxload = 0.0 ;
break ;
1999-11-15 04:57:28 +00:00
case 'q' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_QUIET );
1999-11-15 04:57:28 +00:00
break ;
2004-09-07 01:49:08 +00:00
case 't' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_CACHE_RECORD_FILES );
2004-09-07 01:49:08 +00:00
break ;
2005-03-11 07:24:10 +00:00
case 'T' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_TIMESTAMP );
2005-03-11 07:24:10 +00:00
break ;
2001-05-09 03:11:22 +00:00
case 'x' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_EXEC );
2001-05-09 03:11:22 +00:00
xarg = optarg ;
break ;
2003-02-06 06:15:25 +00:00
case 'C' :
2005-12-04 20:40:46 +00:00
ast_copy_string ( ast_config_AST_CONFIG_FILE , optarg , sizeof ( ast_config_AST_CONFIG_FILE ));
ast_set_flag ( & ast_options , AST_OPT_FLAG_OVERRIDE_CONFIG );
2003-02-06 06:15:25 +00:00
break ;
2006-03-30 06:07:04 +00:00
case 'I' :
2006-03-30 06:26:16 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_INTERNAL_TIMING );
2006-03-30 06:07:04 +00:00
break ;
2001-12-25 21:12:07 +00:00
case 'i' :
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_INIT_KEYS );
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' :
show_cli_help ();
exit ( 0 );
2004-07-18 17:58:05 +00:00
case 'V' :
show_version ();
exit ( 0 );
2004-07-18 16:20:54 +00:00
case 'U' :
runuser = optarg ;
break ;
case 'G' :
rungroup = optarg ;
break ;
1999-11-15 04:57:28 +00:00
case '?' :
exit ( 1 );
}
}
2002-05-14 14:43:52 +00:00
2006-08-08 06:32:04 +00:00
if ( ast_opt_console || option_verbose || ( ast_opt_remote && ! ast_opt_exec )) {
ast_register_verbose ( console_verboser );
WELCOME_MESSAGE ;
}
if ( ast_opt_console && ! option_verbose )
ast_verbose ( "[ Booting... \n " );
2006-04-30 14:55:05 +00:00
if ( ast_opt_always_fork && ( ast_opt_remote || ast_opt_console )) {
ast_log ( LOG_WARNING , "'alwaysfork' is not compatible with console or remote console mode; ignored \n " );
ast_clear_flag ( & ast_options , AST_OPT_FLAG_ALWAYS_FORK );
}
2005-09-29 02:38:24 +00:00
/* For remote connections, change the name of the remote connection.
* We do this for the benefit of init scripts (which need to know if/when
* the main asterisk process has died yet). */
2005-12-04 20:40:46 +00:00
if ( ast_opt_remote ) {
2005-09-29 02:38:24 +00:00
strcpy ( argv [ 0 ], "rasterisk" );
for ( x = 1 ; x < argc ; x ++ ) {
argv [ x ] = argv [ 0 ] + 10 ;
}
}
2006-01-16 23:52:51 +00:00
if ( ast_opt_console && ! option_verbose )
2006-08-08 06:32:04 +00:00
ast_verbose ( "[ Reading Master Configuration ] \n " );
2006-01-16 23:52:51 +00:00
ast_readconfig ();
2006-12-27 21:18:27 +00:00
if ( ! ast_language_is_prefix && ! ast_opt_remote )
ast_log ( LOG_WARNING , "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout. \n " );
2005-12-04 20:40:46 +00:00
if ( ast_opt_dump_core ) {
2003-02-06 06:15:25 +00:00
struct rlimit l ;
memset ( & l , 0 , sizeof ( l ));
l . rlim_cur = RLIM_INFINITY ;
l . rlim_max = RLIM_INFINITY ;
if ( setrlimit ( RLIMIT_CORE , & l )) {
ast_log ( LOG_WARNING , "Unable to disable core size resource limit: %s \n " , strerror ( errno ));
}
}
2005-11-08 00:30:29 +00:00
if (( ! rungroup ) && ! ast_strlen_zero ( ast_config_AST_RUN_GROUP ))
rungroup = ast_config_AST_RUN_GROUP ;
if (( ! runuser ) && ! ast_strlen_zero ( ast_config_AST_RUN_USER ))
runuser = ast_config_AST_RUN_USER ;
2006-03-31 00:33:28 +00:00
2005-11-01 21:53:30 +00:00
#ifndef __CYGWIN__
2005-11-08 02:19:53 +00:00
if ( ! is_child_of_nonroot )
2005-12-04 20:40:46 +00:00
ast_set_priority ( ast_opt_high_priority );
2005-03-26 07:16:18 +00:00
2005-08-23 01:37:26 +00:00
if ( ! is_child_of_nonroot && rungroup ) {
2004-07-18 16:20:54 +00:00
struct group * gr ;
gr = getgrnam ( rungroup );
if ( ! gr ) {
ast_log ( LOG_WARNING , "No such group '%s'! \n " , rungroup );
exit ( 1 );
}
2004-07-18 18:52:36 +00:00
if ( setgid ( gr -> gr_gid )) {
2006-03-02 22:27:50 +00:00
ast_log ( LOG_WARNING , "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 )) {
ast_log ( LOG_WARNING , "Unable to drop unneeded groups \n " );
exit ( 1 );
}
2004-07-18 16:20:54 +00:00
if ( option_verbose )
ast_verbose ( "Running as group '%s' \n " , rungroup );
}
2005-08-23 01:37:26 +00:00
if ( ! is_child_of_nonroot && runuser ) {
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 ) {
ast_log ( LOG_WARNING , "No such user '%s'! \n " , runuser );
exit ( 1 );
}
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 */
2006-01-08 20:27:22 +00:00
if ( ! rungroup ) {
if ( setgid ( pw -> pw_gid )) {
2006-03-02 22:27:50 +00:00
ast_log ( LOG_WARNING , "Unable to setgid to %d! \n " , ( int ) pw -> pw_gid );
2006-01-08 20:27:22 +00:00
exit ( 1 );
}
2006-01-07 20:08:51 +00:00
if ( initgroups ( pw -> pw_name , pw -> pw_gid )) {
ast_log ( LOG_WARNING , "Unable to init groups for '%s' \n " , runuser );
exit ( 1 );
}
2006-01-07 19:42:05 +00:00
}
2004-07-18 16:20:54 +00:00
if ( setuid ( pw -> pw_uid )) {
2006-03-02 22:27:50 +00:00
ast_log ( LOG_WARNING , "Unable to setuid to %d (%s) \n " , ( int ) pw -> pw_uid , runuser );
2004-07-18 16:20:54 +00:00
exit ( 1 );
}
2006-03-31 00:33:28 +00:00
setenv ( "ASTERISK_ALREADY_NONROOT" , "yes" , 1 );
2004-07-18 16:20:54 +00:00
if ( option_verbose )
ast_verbose ( "Running as user '%s' \n " , runuser );
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 ;
2006-09-27 21:48:01 +00:00
cap = cap_from_text ( "cap_net_admin=ep" );
2006-10-02 16:00:11 +00:00
if ( cap_set_proc ( cap ))
2006-09-27 21:48:01 +00:00
ast_log ( LOG_WARNING , "Unable to install capabilities. \n " );
2006-10-02 16:00:11 +00:00
if ( cap_free ( cap ))
2006-09-27 21:48:01 +00:00
ast_log ( LOG_WARNING , "Unable to drop capabilities. \n " );
}
#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 ) {
ast_log ( LOG_WARNING , "Unable to set the process for core dumps after changing to a non-root user. %s \n " , strerror ( errno ));
}
}
2006-02-14 18:47:16 +00:00
#endif
2006-02-14 02:41:42 +00:00
2006-10-04 00:26:21 +00:00
ast_term_init ();
2002-05-14 14:43:52 +00:00
printf ( term_end ());
fflush ( stdout );
2004-06-22 17:42:14 +00:00
2005-12-04 20:40:46 +00:00
if ( ast_opt_console && ! option_verbose )
2006-08-08 06:32:04 +00:00
ast_verbose ( "[ Initializing Custom Configuration Options ] \n " );
2004-06-11 00:12:35 +00:00
/* custom config setup */
register_config_cli ();
2005-01-25 06:10:20 +00:00
read_config_maps ();
2004-06-11 00:12:35 +00:00
2005-12-04 20:40:46 +00:00
if ( ast_opt_console ) {
2004-06-29 04:42:19 +00:00
if ( el_hist == NULL || el == NULL )
ast_el_initialize ();
2003-02-06 06:15:25 +00:00
2004-06-29 04:42:19 +00:00
if ( ! ast_strlen_zero ( filename ))
ast_el_read_history ( filename );
2003-04-16 13:43:11 +00:00
}
2003-02-06 06:15:25 +00:00
2001-05-09 03:11:22 +00:00
if ( ast_tryconnect ()) {
/* One is already running */
2005-12-04 20:40:46 +00:00
if ( ast_opt_remote ) {
if ( ast_opt_exec ) {
2001-05-09 03:11:22 +00:00
ast_remotecontrol ( xarg );
2002-05-14 14:43:52 +00:00
quit_handler ( 0 , 0 , 0 , 0 );
2001-05-09 03:11:22 +00:00
exit ( 0 );
}
2002-05-14 14:43:52 +00:00
printf ( term_quit ());
2001-05-09 03:11:22 +00:00
ast_remotecontrol ( NULL );
2002-05-14 14:43:52 +00:00
quit_handler ( 0 , 0 , 0 , 0 );
2001-05-09 03:11:22 +00:00
exit ( 0 );
} else {
2005-12-04 20:40:46 +00:00
ast_log ( LOG_ERROR , "Asterisk already running on %s. Use 'asterisk -r' to connect. \n " , ast_config_AST_SOCKET );
2002-05-14 14:43:52 +00:00
printf ( 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 ) {
2006-03-31 00:33:28 +00:00
ast_log ( LOG_ERROR , "Unable to connect to remote asterisk (does %s exist?) \n " , ast_config_AST_SOCKET );
2002-05-14 14:43:52 +00:00
printf ( term_quit ());
2001-05-09 03:11:22 +00:00
exit ( 1 );
}
2002-09-12 03:22:07 +00:00
/* Blindly write pid file since we couldn't connect */
2005-12-04 20:40:46 +00:00
unlink ( ast_config_AST_PID );
f = fopen ( ast_config_AST_PID , "w" );
2002-09-12 03:22:07 +00:00
if ( f ) {
2006-05-08 12:32:44 +00:00
fprintf ( f , "%ld \n " , ( long ) getpid ());
2002-09-12 03:22:07 +00:00
fclose ( f );
} else
2005-12-04 20:40:46 +00:00
ast_log ( LOG_WARNING , "Unable to open pid file '%s': %s \n " , ast_config_AST_PID , strerror ( errno ));
2001-12-25 21:12:07 +00:00
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 ) {
2006-03-31 00:33:28 +00:00
daemon ( 0 , 0 );
2006-05-08 12:32:44 +00:00
ast_mainpid = getpid ();
2003-10-16 10:27:41 +00:00
/* Blindly re-write pid file since we are forking */
2005-12-04 20:40:46 +00:00
unlink ( ast_config_AST_PID );
f = fopen ( ast_config_AST_PID , "w" );
2003-10-16 10:27:41 +00:00
if ( f ) {
2006-05-08 12:32:44 +00:00
fprintf ( f , "%ld \n " , ( long ) ast_mainpid );
2003-10-16 10:27:41 +00:00
fclose ( f );
} else
2005-12-04 20:40:46 +00:00
ast_log ( LOG_WARNING , "Unable to open pid file '%s': %s \n " , ast_config_AST_PID , strerror ( errno ));
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
2004-09-28 17:11:30 +00:00
/* Test recursive mutex locking. */
if ( test_for_thread_safety ())
ast_verbose ( "Warning! Asterisk is not thread safe. \n " );
2001-05-09 03:11:22 +00:00
ast_makesocket ();
sigemptyset ( & sigs );
sigaddset ( & sigs , SIGHUP );
sigaddset ( & sigs , SIGTERM );
sigaddset ( & sigs , SIGINT );
sigaddset ( & sigs , SIGPIPE );
sigaddset ( & sigs , SIGWINCH );
pthread_sigmask ( SIG_BLOCK , & sigs , NULL );
1999-11-15 04:57:28 +00:00
signal ( SIGURG , urg_handler );
2002-05-14 14:43:52 +00:00
signal ( SIGINT , __quit_handler );
signal ( SIGTERM , __quit_handler );
2001-05-09 03:11:22 +00:00
signal ( SIGHUP , hup_handler );
2003-09-16 19:35:57 +00:00
signal ( SIGCHLD , child_handler );
signal ( SIGPIPE , SIG_IGN );
2005-04-13 04:47:39 +00:00
/* ensure that the random number generators are seeded with a different value every time
Asterisk is started
*/
srand (( unsigned int ) getpid () + ( unsigned int ) time ( NULL ));
2006-01-10 00:55:45 +00:00
initstate (( unsigned int ) getpid () * 65536 + ( unsigned int ) time ( NULL ), randompool , sizeof ( randompool ));
2005-04-13 04:47:39 +00:00
2006-10-29 20:47:01 +00:00
if ( init_logger ()) { /* Start logging subsystem */
2002-05-14 14:43:52 +00:00
printf ( term_quit ());
1999-11-15 04:57:28 +00:00
exit ( 1 );
2002-05-14 14:43:52 +00:00
}
2007-01-04 23:18:36 +00:00
threadstorage_init ();
2006-10-29 20:47:01 +00:00
if ( load_modules ( 1 )) { /* Load modules */
2005-08-14 23:47:40 +00:00
printf ( term_quit ());
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2006-10-29 20:47:01 +00:00
if ( dnsmgr_init ()) { /* Initialize the DNS manager */
2005-07-05 22:11:43 +00:00
printf ( term_quit ());
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2006-10-29 20:47:01 +00:00
ast_http_init (); /* Start the HTTP server, if needed */
2006-08-21 02:11:39 +00:00
2004-12-31 00:04:41 +00:00
ast_channels_init ();
2006-08-21 02:11:39 +00:00
2002-09-12 03:22:07 +00:00
if ( init_manager ()) {
printf ( term_quit ());
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2005-06-03 01:42:31 +00:00
if ( ast_cdr_engine_init ()) {
printf ( term_quit ());
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2005-07-08 21:14:34 +00:00
if ( ast_device_state_engine_init ()) {
printf ( term_quit ());
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2003-05-16 02:50:46 +00:00
ast_rtp_init ();
2006-08-21 02:11:39 +00:00
2006-01-12 17:14:58 +00:00
ast_udptl_init ();
2006-08-21 02:11:39 +00:00
2002-05-14 14:43:52 +00:00
if ( ast_image_init ()) {
printf ( term_quit ());
2001-10-11 18:51:39 +00:00
exit ( 1 );
2002-05-14 14:43:52 +00:00
}
2006-08-21 02:11:39 +00:00
2004-06-30 03:22:29 +00:00
if ( ast_file_init ()) {
printf ( term_quit ());
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2002-05-14 14:43:52 +00:00
if ( load_pbx ()) {
printf ( term_quit ());
1999-11-15 04:57:28 +00:00
exit ( 1 );
2002-05-14 14:43:52 +00:00
}
2006-08-21 02:11:39 +00:00
2002-05-14 14:43:52 +00:00
if ( init_framer ()) {
printf ( term_quit ());
2001-10-11 18:51:39 +00:00
exit ( 1 );
2002-05-14 14:43:52 +00:00
}
2006-08-21 02:11:39 +00:00
2003-02-06 06:15:25 +00:00
if ( astdb_init ()) {
printf ( term_quit ());
exit ( 1 );
}
2006-08-21 02:11:39 +00:00
2003-05-01 04:29:25 +00:00
if ( ast_enum_init ()) {
printf ( term_quit ());
exit ( 1 );
}
2005-11-08 01:29:14 +00:00
2006-08-21 22:23:26 +00:00
if ( load_modules ( 0 )) {
printf ( term_quit ());
exit ( 1 );
}
2005-11-08 01:29:14 +00:00
dnsmgr_start_refresh ();
1999-11-15 04:57:28 +00:00
/* We might have the option of showing a console, but for now just
do nothing... */
2005-12-04 20:40:46 +00:00
if ( ast_opt_console && ! option_verbose )
2000-01-02 20:59:00 +00:00
ast_verbose ( " ] \n " );
2005-12-04 20:40:46 +00:00
if ( option_verbose || ast_opt_console )
2002-05-14 14:43:52 +00:00
ast_verbose ( term_color ( tmp , "Asterisk Ready. \n " , COLOR_BRWHITE , COLOR_BLACK , sizeof ( tmp )));
2005-12-04 20:40:46 +00:00
if ( ast_opt_no_fork )
2004-03-02 23:50:03 +00:00
consolethread = pthread_self ();
2006-08-21 02:11:39 +00:00
2005-12-04 20:40:46 +00:00
ast_set_flag ( & ast_options , AST_OPT_FLAG_FULLY_BOOTED );
2001-05-09 03:11:22 +00:00
pthread_sigmask ( SIG_UNBLOCK , & sigs , NULL );
2006-08-21 02:11:39 +00:00
2003-04-28 19:58:43 +00:00
#ifdef __AST_DEBUG_MALLOC
__ast_mm_init ();
#endif
2006-08-21 02:11:39 +00:00
2003-05-02 15:37:34 +00:00
time ( & ast_startuptime );
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( cli_asterisk , sizeof ( cli_asterisk ) / sizeof ( struct ast_cli_entry ));
2006-08-21 02:11:39 +00:00
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 ];
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
2003-05-22 14:24:06 +00:00
for (;;) {
buf = ( char * ) el_gets ( el , & num );
if ( buf ) {
if ( buf [ strlen ( buf ) - 1 ] == '\n' )
buf [ strlen ( buf ) - 1 ] = '\0' ;
consolehandler (( char * ) buf );
2006-09-26 21:01:02 +00:00
} else if ( ast_opt_remote && ( write ( STDOUT_FILENO , " \n Use EXIT or QUIT to exit the asterisk console \n " ,
strlen ( " \n Use EXIT or QUIT to exit the asterisk console \n " )) < 0 )) {
/* Whoa, stdout disappeared from under us... Make /dev/null's */
int fd ;
fd = open ( "/dev/null" , O_RDWR );
if ( fd > - 1 ) {
dup2 ( fd , STDOUT_FILENO );
dup2 ( fd , STDIN_FILENO );
} else
ast_log ( LOG_WARNING , "Failed to open /dev/null to recover from dead console. Bad things will happen! \n " );
break ;
2003-08-21 02:34:03 +00:00
}
2007-01-30 17:23:56 +00:00
if ( need_reload ) {
need_reload = 0 ;
ast_module_reload ( NULL );
}
2003-02-06 06:15:25 +00:00
}
2000-01-02 20:59:00 +00:00
}
2005-01-15 08:53:28 +00:00
/* Do nothing */
2006-08-21 20:12:18 +00:00
for (;;) { /* apparently needed for Mac OS X */
2005-06-03 02:41:59 +00:00
struct pollfd p = { - 1 /* no descriptor */ , 0 , 0 };
poll ( & p , 0 , - 1 );
2007-01-30 17:23:56 +00:00
/* SIGHUP will cause this to break out of poll() */
if ( need_reload ) {
need_reload = 0 ;
ast_module_reload ( NULL );
}
2005-06-03 02:41:59 +00:00
}
2006-08-21 20:12:18 +00:00
1999-11-15 04:57:28 +00:00
return 0 ;
}