1999-11-15 04:57:28 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
* Top level source file for asterisk
*
1999-12-19 22:38:55 +00:00
* Copyright ( C ) 1999 , Mark Spencer
1999-11-15 04:57:28 +00:00
*
* Mark Spencer < markster @ linux - support . net >
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
# include <unistd.h>
# include <stdlib.h>
2004-04-25 20:42:45 +00:00
# include <sys/poll.h>
1999-11-15 04:57:28 +00:00
# include <asterisk/logger.h>
# include <asterisk/options.h>
1999-12-19 22:38:55 +00:00
# include <asterisk/cli.h>
2000-01-09 19:58:18 +00:00
# include <asterisk/channel.h>
2001-03-22 04:14:04 +00:00
# include <asterisk/ulaw.h>
2001-12-25 21:12:07 +00:00
# include <asterisk/alaw.h>
2001-03-22 04:14:04 +00:00
# include <asterisk/callerid.h>
2001-05-09 03:11:22 +00:00
# include <asterisk/module.h>
2001-10-11 18:51:39 +00:00
# include <asterisk/image.h>
2001-12-25 21:12:07 +00:00
# include <asterisk/tdd.h>
2002-05-14 14:43:52 +00:00
# include <asterisk/term.h>
2002-09-12 03:22:07 +00:00
# include <asterisk/manager.h>
2003-02-06 06:15:25 +00:00
# include <asterisk/pbx.h>
2003-05-01 04:29:25 +00:00
# include <asterisk/enum.h>
2003-05-16 02:50:46 +00:00
# include <asterisk/rtp.h>
2004-03-21 18:15:37 +00:00
# include <asterisk/app.h>
2004-04-22 05:11:11 +00:00
# include <asterisk/lock.h>
2003-02-06 06:15:25 +00:00
# include <sys/resource.h>
2001-10-11 18:51:39 +00:00
# include <fcntl.h>
1999-11-15 04:57:28 +00:00
# include <stdio.h>
# include <signal.h>
1999-12-19 22:38:55 +00:00
# include <sched.h>
2001-12-25 21:12:07 +00:00
# include <asterisk/io.h>
2004-03-15 07:51:22 +00:00
# include <asterisk/lock.h>
2001-05-09 03:11:22 +00:00
# include <sys/socket.h>
# include <sys/un.h>
2003-09-17 04:21:56 +00:00
# include <sys/wait.h>
2001-05-09 03:11:22 +00:00
# include <string.h>
# include <errno.h>
2003-02-06 06:15:25 +00:00
# include <ctype.h>
# include "editline/histedit.h"
1999-11-15 04:57:28 +00:00
# include "asterisk.h"
2003-02-06 06:15:25 +00:00
# include <asterisk/config.h>
1999-11-15 04:57:28 +00:00
2004-04-28 13:53:01 +00:00
# if defined(__FreeBSD__)
# include <netdb.h>
# endif
2001-05-09 03:11:22 +00:00
# define AST_MAX_CONNECTS 128
# define NUM_MSGS 64
1999-11-15 04:57:28 +00:00
int option_verbose = 0 ;
int option_debug = 0 ;
int option_nofork = 0 ;
int option_quiet = 0 ;
2000-01-02 20:59:00 +00:00
int option_console = 0 ;
1999-12-19 22:38:55 +00:00
int option_highpriority = 0 ;
2001-05-09 03:11:22 +00:00
int option_remote = 0 ;
int option_exec = 0 ;
2001-12-25 21:12:07 +00:00
int option_initcrypto = 0 ;
2002-05-14 14:43:52 +00:00
int option_nocolor ;
2003-02-06 06:15:25 +00:00
int option_dumpcore = 0 ;
int option_overrideconfig = 0 ;
2000-01-02 20:59:00 +00:00
int fully_booted = 0 ;
1999-12-19 22:38:55 +00:00
2001-05-09 03:11:22 +00:00
static int ast_socket = - 1 ; /* UNIX Socket for allowing remote control */
static int ast_consock = - 1 ; /* UNIX Socket for controlling another asterisk */
2004-03-20 21:13:12 +00:00
int ast_mainpid ;
2001-05-09 03:11:22 +00:00
struct console {
int fd ; /* File descriptor */
int p [ 2 ] ; /* Pipe */
pthread_t t ; /* Thread of handler */
} ;
2003-08-07 03:48:00 +00:00
static struct ast_atexit {
void ( * func ) ( void ) ;
struct ast_atexit * next ;
} * atexits = NULL ;
2003-08-13 15:25:16 +00:00
static ast_mutex_t atexitslock = AST_MUTEX_INITIALIZER ;
2003-08-07 03:48:00 +00:00
2003-05-02 15:37:34 +00:00
time_t ast_startuptime ;
time_t ast_lastreloadtime ;
2003-02-06 06:15:25 +00:00
static History * el_hist = NULL ;
static EditLine * el = NULL ;
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 * ) ;
char ast_config_AST_CONFIG_DIR [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_CONFIG_FILE [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_MODULE_DIR [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_SPOOL_DIR [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_VAR_DIR [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_LOG_DIR [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_AGI_DIR [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_DB [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_KEY_DIR [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_PID [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_SOCKET [ AST_CONFIG_MAX_PATH ] ;
char ast_config_AST_RUN_DIR [ AST_CONFIG_MAX_PATH ] ;
2004-02-23 03:43:21 +00:00
static char * _argv [ 256 ] ;
static int shuttingdown = 0 ;
static int restartnow = 0 ;
2004-03-15 07:51:22 +00:00
static pthread_t consolethread = AST_PTHREADT_NULL ;
2004-02-23 03:43:21 +00:00
2003-08-07 03:48:00 +00:00
int ast_register_atexit ( void ( * func ) ( void ) )
{
int res = - 1 ;
struct ast_atexit * ae ;
ast_unregister_atexit ( func ) ;
ae = malloc ( sizeof ( struct ast_atexit ) ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & atexitslock ) ;
2003-08-07 03:48:00 +00:00
if ( ae ) {
memset ( ae , 0 , sizeof ( struct ast_atexit ) ) ;
ae - > next = atexits ;
ae - > func = func ;
atexits = ae ;
res = 0 ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & atexitslock ) ;
2003-08-07 03:48:00 +00:00
return res ;
}
void ast_unregister_atexit ( void ( * func ) ( void ) )
{
struct ast_atexit * ae , * prev = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & atexitslock ) ;
2003-08-07 03:48:00 +00:00
ae = atexits ;
while ( ae ) {
if ( ae - > func = = func ) {
if ( prev )
prev - > next = ae - > next ;
else
atexits = ae - > next ;
break ;
}
prev = ae ;
ae = ae - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & atexitslock ) ;
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 ) ;
}
2004-03-21 18:15:37 +00:00
int ast_safe_system ( const char * s )
{
/* XXX This function needs some optimization work XXX */
pid_t pid ;
int x ;
int res ;
struct rusage rusage ;
int status ;
pid = fork ( ) ;
if ( pid = = 0 ) {
/* Close file descriptors and launch system command */
for ( x = STDERR_FILENO + 1 ; x < 4096 ; x + + ) {
close ( x ) ;
}
2004-03-23 21:55:46 +00:00
res = execl ( " /bin/sh " , " /bin/sh " , " -c " , s , NULL ) ;
exit ( 1 ) ;
2004-03-21 18:15:37 +00:00
} else if ( pid > 0 ) {
for ( ; ; ) {
res = wait4 ( pid , & status , 0 , & rusage ) ;
if ( res > - 1 ) {
if ( WIFEXITED ( status ) )
res = WEXITSTATUS ( status ) ;
else
res = - 1 ;
} else {
if ( errno ! = EINTR )
break ;
}
}
} else {
ast_log ( LOG_WARNING , " Fork failed: %s \n " , strerror ( errno ) ) ;
res = - 1 ;
}
return res ;
}
2004-01-12 05:05:35 +00:00
/*
* write the string to all attached console clients
*/
static void ast_network_puts ( const char * string )
{
int x ;
for ( x = 0 ; x < AST_MAX_CONNECTS ; x + + ) {
if ( consoles [ x ] . fd > - 1 )
fdprint ( consoles [ x ] . p [ 1 ] , string ) ;
}
}
/*
* write the string to the console , and all attached
* console clients
*/
void ast_console_puts ( const char * string )
{
fputs ( string , stdout ) ;
fflush ( stdout ) ;
ast_network_puts ( string ) ;
}
2003-03-16 22:37:31 +00:00
static void network_verboser ( const char * s , int pos , int replace , int complete )
2004-01-12 05:05:35 +00:00
/* ARGUSED */
2001-05-09 03:11:22 +00:00
{
2004-01-12 05:05:35 +00:00
ast_network_puts ( s ) ;
2001-05-09 03:11:22 +00:00
}
static pthread_t lthread ;
static void * netconsole ( void * vconsole )
{
struct console * con = vconsole ;
char hostname [ 256 ] ;
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
if ( gethostname ( hostname , sizeof ( hostname ) ) )
2001-12-25 21:12:07 +00:00
strncpy ( hostname , " <Unknown> " , sizeof ( hostname ) - 1 ) ;
2004-03-20 21:13:12 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %s/%d/%s \n " , hostname , ast_mainpid , ASTERISK_VERSION ) ;
2001-05-09 03:11:22 +00:00
fdprint ( con - > fd , tmp ) ;
for ( ; ; ) {
2004-04-25 20:42:45 +00:00
fds [ 0 ] . fd = con - > fd ;
fds [ 0 ] . events = POLLIN ;
fds [ 1 ] . fd = con - > p [ 0 ] ;
fds [ 1 ] . events = POLLIN ;
res = poll ( fds , 2 , - 1 ) ;
2001-05-09 03:11:22 +00:00
if ( res < 0 ) {
2004-04-25 20:42:45 +00:00
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 )
{
struct sockaddr_un sun ;
int s ;
int len ;
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 ) ;
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 ;
fds [ 0 ] . events = POLLIN ;
s = poll ( fds , 1 , - 1 ) ;
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 ;
}
2001-05-09 03:11:22 +00:00
len = sizeof ( sun ) ;
s = accept ( ast_socket , ( struct sockaddr * ) & sun , & len ) ;
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 {
for ( x = 0 ; x < AST_MAX_CONNECTS ; x + + ) {
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 ;
if ( pthread_create ( & consoles [ x ] . t , & attr , netconsole , & consoles [ x ] ) ) {
ast_log ( LOG_ERROR , " Unable to spawn thread to handle connection \n " ) ;
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 )
{
struct sockaddr_un sun ;
int res ;
int x ;
for ( x = 0 ; x < AST_MAX_CONNECTS ; x + + )
consoles [ x ] . fd = - 1 ;
2003-02-06 06:15:25 +00:00
unlink ( ( char * ) 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 ;
}
memset ( & sun , 0 , sizeof ( sun ) ) ;
sun . sun_family = AF_LOCAL ;
2003-02-06 06:15:25 +00:00
strncpy ( sun . sun_path , ( char * ) ast_config_AST_SOCKET , sizeof ( sun . sun_path ) - 1 ) ;
2001-05-09 03:11:22 +00:00
res = bind ( ast_socket , ( struct sockaddr * ) & sun , sizeof ( sun ) ) ;
if ( res ) {
2003-02-06 06:15:25 +00:00
ast_log ( LOG_WARNING , " Unable to bind socket to %s: %s \n " , ( char * ) 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 ) {
2003-02-06 06:15:25 +00:00
ast_log ( LOG_WARNING , " Unable to listen on socket %s: %s \n " , ( char * ) 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 ) ;
pthread_create ( & lthread , NULL , listener , NULL ) ;
return 0 ;
}
static int ast_tryconnect ( void )
{
struct sockaddr_un sun ;
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 ;
}
memset ( & sun , 0 , sizeof ( sun ) ) ;
sun . sun_family = AF_LOCAL ;
2003-02-06 06:15:25 +00:00
strncpy ( sun . sun_path , ( char * ) ast_config_AST_SOCKET , sizeof ( sun . sun_path ) - 1 ) ;
2001-05-09 03:11:22 +00:00
res = connect ( ast_consock , ( struct sockaddr * ) & sun , sizeof ( sun ) ) ;
if ( res ) {
close ( ast_consock ) ;
ast_consock = - 1 ;
return 0 ;
} else
return 1 ;
}
1999-11-15 04:57:28 +00:00
static void urg_handler ( int num )
{
2004-04-25 20:42:45 +00:00
/* Called by soft_hangup to interrupt the poll, read, or other
1999-11-15 04:57:28 +00:00
system call . We don ' t actually need to do anything though . */
2003-12-01 02:47:19 +00:00
/* Cannot EVER ast_log from within a signal handler */
2001-05-09 03:11:22 +00:00
if ( option_debug )
2003-12-01 02:47:19 +00:00
printf ( " Urgent handler \n " ) ;
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 ) ;
2003-12-01 02:47:19 +00:00
/* XXX This could deadlock XXX */
2001-05-09 03:11:22 +00:00
ast_module_reload ( ) ;
}
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 " ) ;
2001-05-09 03:11:22 +00:00
}
2003-09-16 19:35:57 +00:00
2000-10-25 23:22:50 +00:00
static void set_title ( char * text )
{
/* Set an X-term or screen title */
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 ) ;
}
1999-12-19 22:38:55 +00:00
static int set_priority ( int pri )
{
struct sched_param sched ;
2001-03-22 04:14:04 +00:00
memset ( & sched , 0 , sizeof ( sched ) ) ;
1999-12-19 22:38:55 +00:00
/* We set ourselves to a high priority, that we might pre-empt everything
else . If your PBX has heavy activity on it , this is a good thing . */
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 ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & atexitslock ) ;
2003-08-07 03:48:00 +00:00
ae = atexits ;
while ( ae ) {
if ( ae - > func )
ae - > func ( ) ;
ae = ae - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & atexitslock ) ;
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 ;
if ( safeshutdown ) {
shuttingdown = 1 ;
if ( ! nice ) {
/* Begin shutdown routine, hanging up active channels */
ast_begin_shutdown ( 1 ) ;
if ( option_verbose & & option_console )
ast_verbose ( " Beginning asterisk %s.... \n " , restart ? " restart " : " shutdown " ) ;
time ( & s ) ;
for ( ; ; ) {
time ( & e ) ;
/* Wait up to 15 seconds for all channels to go away */
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 ) ;
if ( option_verbose & & option_console )
ast_verbose ( " Waiting for inactivity to perform %s... \n " , restart ? " restart " : " halt " ) ;
for ( ; ; ) {
if ( ! ast_active_channels ( ) )
break ;
if ( ! shuttingdown )
break ;
sleep ( 1 ) ;
}
}
if ( ! shuttingdown ) {
if ( option_verbose & & option_console )
ast_verbose ( " Asterisk %s cancelled. \n " , restart ? " restart " : " shutdown " ) ;
return ;
}
}
2001-05-09 03:11:22 +00:00
if ( option_console | | option_remote ) {
if ( getenv ( " HOME " ) )
snprintf ( filename , sizeof ( filename ) , " %s/.asterisk_history " , getenv ( " HOME " ) ) ;
if ( strlen ( 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 */
2001-05-09 03:11:22 +00:00
if ( option_verbose & & option_console )
2002-05-14 14:43:52 +00:00
ast_verbose ( " Asterisk %s ending (%d). \n " , ast_active_channels ( ) ? " uncleanly " : " cleanly " , num ) ;
1999-11-15 04:57:28 +00:00
else if ( option_debug )
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 ) {
2001-05-09 03:11:22 +00:00
close ( ast_socket ) ;
2002-09-12 03:22:07 +00:00
ast_socket = - 1 ;
}
2001-05-09 03:11:22 +00:00
if ( ast_consock > - 1 )
close ( ast_consock ) ;
if ( ast_socket > - 1 )
2003-02-06 06:15:25 +00:00
unlink ( ( char * ) ast_config_AST_SOCKET ) ;
2003-07-09 13:45:59 +00:00
if ( ! option_remote ) unlink ( ( char * ) ast_config_AST_PID ) ;
2002-05-14 14:43:52 +00:00
printf ( term_quit ( ) ) ;
if ( restart ) {
if ( option_verbose | | option_console )
ast_verbose ( " Preparing for Asterisk restart... \n " ) ;
/* Mark all FD's for closing on exec */
for ( x = 3 ; x < 32768 ; x + + ) {
fcntl ( x , F_SETFD , FD_CLOEXEC ) ;
}
if ( option_verbose | | option_console )
ast_verbose ( " Restarting Asterisk NOW... \n " ) ;
2004-02-23 03:43:21 +00:00
restartnow = 1 ;
/* If there is a consolethread running send it a SIGHUP
so it can execvp , otherwise we can do it ourselves */
2004-03-15 07:51:22 +00:00
if ( consolethread ! = AST_PTHREADT_NULL ) {
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 ) ;
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
}
2003-03-16 22:37:31 +00:00
static void console_verboser ( const char * s , int pos , int replace , int complete )
1999-12-19 22:38:55 +00:00
{
2002-05-14 14:43:52 +00:00
char tmp [ 80 ] ;
2003-06-27 23:02:52 +00:00
const char * c = NULL ;
1999-12-19 22:38:55 +00:00
/* Return to the beginning of the line */
2002-05-14 14:43:52 +00:00
if ( ! pos ) {
1999-12-19 22:38:55 +00:00
fprintf ( stdout , " \r " ) ;
2003-06-27 23:02:52 +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 ) ) )
2002-05-14 14:43:52 +00:00
fputs ( tmp , stdout ) ;
}
2003-06-27 23:02:52 +00:00
if ( c )
fputs ( c + pos , stdout ) ;
else
fputs ( s + pos , stdout ) ;
2000-01-02 20:59:00 +00:00
fflush ( stdout ) ;
1999-12-19 22:38:55 +00:00
if ( complete )
2004-04-25 20:42:45 +00:00
/* Wake up a poll()ing console */
2004-03-15 07:51:22 +00:00
if ( option_console & & consolethread ! = AST_PTHREADT_NULL )
2002-09-12 03:22:07 +00:00
pthread_kill ( consolethread , SIGURG ) ;
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 ) ;
1999-12-19 22:38:55 +00:00
/* Called when readline data is available */
if ( s & & strlen ( s ) )
2003-02-06 06:15:25 +00:00
ast_el_add_history ( s ) ;
2000-01-02 20:59:00 +00:00
/* Give the console access to the shell */
if ( s ) {
2003-10-22 03:46:36 +00:00
/* The real handler for bang */
2000-01-02 20:59:00 +00:00
if ( s [ 0 ] = = ' ! ' ) {
if ( s [ 1 ] )
2004-03-21 18:15:37 +00:00
ast_safe_system ( s + 1 ) ;
2000-01-02 20:59:00 +00:00
else
2004-03-21 18:15:37 +00:00
ast_safe_system ( getenv ( " SHELL " ) ? getenv ( " SHELL " ) : " /bin/sh " ) ;
2000-01-02 20:59:00 +00:00
} else
1999-12-19 22:38:55 +00:00
ast_cli_command ( STDOUT_FILENO , s ) ;
2000-01-02 20:59:00 +00:00
} else
fprintf ( stdout , " \n Use \" quit \" to exit \n " ) ;
1999-12-19 22:38:55 +00:00
}
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 ;
2001-05-09 03:11:22 +00:00
/* Called when readline data is available */
if ( s & & strlen ( s ) )
2003-02-06 06:15:25 +00:00
ast_el_add_history ( s ) ;
2001-05-09 03:11:22 +00:00
/* Give the console access to the shell */
if ( s ) {
2003-10-22 03:46:36 +00:00
/* The real handler for bang */
2001-05-09 03:11:22 +00:00
if ( s [ 0 ] = = ' ! ' ) {
if ( s [ 1 ] )
2004-03-21 18:15:37 +00:00
ast_safe_system ( s + 1 ) ;
2001-05-09 03:11:22 +00:00
else
2004-03-21 18:15:37 +00:00
ast_safe_system ( getenv ( " SHELL " ) ? getenv ( " SHELL " ) : " /bin/sh " ) ;
2003-02-06 06:15:25 +00:00
ret = 1 ;
}
2003-09-04 03:55:41 +00:00
if ( ( strncasecmp ( s , " quit " , 4 ) = = 0 | | strncasecmp ( s , " exit " , 4 ) = = 0 ) & &
( s [ 4 ] = = ' \0 ' | | isspace ( s [ 4 ] ) ) ) {
2002-05-14 14:43:52 +00:00
quit_handler ( 0 , 0 , 0 , 0 ) ;
2003-02-06 06:15:25 +00:00
ret = 1 ;
}
2001-05-09 03:11:22 +00:00
} else
fprintf ( stdout , " \n Use \" quit \" to exit \n " ) ;
2003-02-06 06:15:25 +00:00
return ret ;
2001-05-09 03:11:22 +00:00
}
1999-12-19 22:38:55 +00:00
static char quit_help [ ] =
" Usage: quit \n "
" Exits Asterisk. \n " ;
2002-05-14 14:43:52 +00:00
static char abort_halt_help [ ] =
" Usage: abort shutdown \n "
" Causes Asterisk to abort an executing shutdown or restart, and resume normal \n "
" call operations. \n " ;
static char shutdown_now_help [ ] =
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 " ;
static 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 " ;
2003-04-23 16:24:09 +00:00
static char shutdown_when_convenient_help [ ] =
" Usage: stop when convenient \n "
" Causes Asterisk to perform a shutdown when all active calls have ended. \n " ;
2002-05-14 14:43:52 +00:00
static char restart_now_help [ ] =
" Usage: restart now \n "
" Causes Asterisk to hangup all calls and exec() itself performing a cold. \n "
" restart. \n " ;
static char restart_gracefully_help [ ] =
" Usage: restart gracefully \n "
" Causes Asterisk to stop accepting new calls and exec() itself performing a cold. \n "
" restart when all active calls have ended. \n " ;
static char restart_when_convenient_help [ ] =
" 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
2003-10-22 03:46:36 +00:00
static char bang_help [ ] =
" Usage: !<command> \n "
" Executes a given shell command \n " ;
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
2003-02-06 06:15:25 +00:00
static int no_more_quit ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 1 )
return RESULT_SHOWUSAGE ;
ast_cli ( fd , " The QUIT and EXIT commands may no longer be used to shutdown the PBX. \n "
" Please use STOP NOW instead, if you wish to shutdown the PBX. \n " ) ;
return RESULT_SUCCESS ;
}
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 ;
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 ;
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 ;
}
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> "
2002-05-14 14:43:52 +00:00
static struct ast_cli_entry aborthalt = { { " abort " , " halt " , NULL } , handle_abort_halt , " Cancel a running halt " , abort_halt_help } ;
2003-02-06 06:15:25 +00:00
static struct ast_cli_entry quit = { { " quit " , NULL } , no_more_quit , " Exit Asterisk " , quit_help } ;
static struct ast_cli_entry astexit = { { " exit " , NULL } , no_more_quit , " Exit Asterisk " , quit_help } ;
1999-12-19 22:38:55 +00:00
2003-12-09 20:37:10 +00:00
static struct ast_cli_entry astshutdownnow = { { " stop " , " now " , NULL } , handle_shutdown_now , " Shut down Asterisk immediately " , shutdown_now_help } ;
2003-02-06 06:15:25 +00:00
static struct ast_cli_entry astshutdowngracefully = { { " stop " , " gracefully " , NULL } , handle_shutdown_gracefully , " Gracefully shut down Asterisk " , shutdown_gracefully_help } ;
2003-04-23 16:24:09 +00:00
static struct ast_cli_entry astshutdownwhenconvenient = { { " stop " , " when " , " convenient " , NULL } , handle_shutdown_when_convenient , " Shut down Asterisk at empty call volume " , shutdown_when_convenient_help } ;
2002-05-14 14:43:52 +00:00
static struct ast_cli_entry astrestartnow = { { " restart " , " now " , NULL } , handle_restart_now , " Restart Asterisk immediately " , restart_now_help } ;
static struct ast_cli_entry astrestartgracefully = { { " restart " , " gracefully " , NULL } , handle_restart_gracefully , " Restart Asterisk gracefully " , restart_gracefully_help } ;
static struct ast_cli_entry astrestartwhenconvenient = { { " restart " , " when " , " convenient " , NULL } , handle_restart_when_convenient , " Restart Asterisk at empty call volume " , restart_when_convenient_help } ;
2003-10-22 03:46:36 +00:00
static struct ast_cli_entry astbang = { { " ! " , NULL } , handle_bang , " Execute a shell command " , bang_help } ;
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 )
{
2004-04-25 20:42:45 +00:00
int num_read = 0 ;
2003-02-06 06:15:25 +00:00
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 ;
2003-06-23 16:40:12 +00:00
if ( ! option_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 ;
}
2004-04-25 20:42:45 +00:00
if ( ! option_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 " ) ;
quit_handler ( 0 , 0 , 0 , 0 ) ;
}
buf [ res ] = ' \0 ' ;
2003-06-23 16:40:12 +00:00
if ( ! option_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 ) ;
2003-02-06 06:15:25 +00:00
} else {
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 ;
if ( ( pfmt = getenv ( " ASTERISK_PROMPT " ) ) ) {
char * t = pfmt , * p = prompt ;
memset ( prompt , 0 , sizeof ( prompt ) ) ;
while ( * t ! = ' \0 ' & & * p < sizeof ( prompt ) ) {
if ( * t = = ' % ' ) {
t + + ;
switch ( * t ) {
char hostname [ 256 ] ;
struct timeval tv ;
struct tm tm ;
FILE * LOADAVG ;
case ' d ' : /* date */
memset ( & tm , 0 , sizeof ( struct tm ) ) ;
gettimeofday ( & tv , NULL ) ;
if ( localtime_r ( & ( tv . tv_sec ) , & tm ) ) {
strftime ( p , sizeof ( prompt ) - strlen ( prompt ) , " %Y-%m-%d " , & tm ) ;
}
break ;
case ' h ' : /* hostname */
if ( ! gethostname ( hostname , sizeof ( hostname ) - 1 ) ) {
strncat ( p , hostname , sizeof ( prompt ) - strlen ( prompt ) ) ;
} else {
strncat ( p , " localhost " , sizeof ( prompt ) - strlen ( prompt ) ) ;
}
break ;
# ifdef linux
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 ;
}
}
}
break ;
# endif
case ' t ' : /* time */
memset ( & tm , 0 , sizeof ( struct tm ) ) ;
gettimeofday ( & tv , NULL ) ;
if ( localtime_r ( & ( tv . tv_sec ) , & tm ) ) {
strftime ( p , sizeof ( prompt ) - strlen ( prompt ) , " %H:%M:%S " , & tm ) ;
}
break ;
case ' # ' : /* process console or remote? */
if ( ! option_remote ) {
strncat ( p , " # " , sizeof ( prompt ) - strlen ( prompt ) ) ;
} else {
strncat ( p , " > " , sizeof ( prompt ) - strlen ( prompt ) ) ;
}
break ;
case ' % ' : /* literal % */
strncat ( p , " % " , sizeof ( prompt ) - strlen ( prompt ) ) ;
break ;
case ' \0 ' : /* % is last character - prevent bug */
t - - ;
break ;
}
while ( * p ! = ' \0 ' ) {
p + + ;
}
t + + ;
} else {
* p = * t ;
p + + ;
t + + ;
}
}
} 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 ;
size_t match_list_len ;
int matches = 0 ;
match_list_len = 1 ;
while ( ( retstr = strsep ( & buf , " " ) ) ! = NULL ) {
2004-04-06 07:42:01 +00:00
if ( ! strcmp ( retstr , AST_CLI_COMPLETE_EOF ) )
break ;
2003-02-06 06:15:25 +00:00
if ( matches + 1 > = match_list_len ) {
match_list_len < < = 1 ;
match_list = realloc ( match_list , match_list_len * sizeof ( char * ) ) ;
}
2004-04-07 18:26:24 +00:00
match_list [ matches + + ] = strdup ( retstr ) ;
2003-02-06 06:15:25 +00:00
}
if ( ! match_list )
return ( char * * ) NULL ;
if ( matches > = match_list_len )
match_list = realloc ( match_list , ( match_list_len + 1 ) * sizeof ( char * ) ) ;
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 ;
qsort ( & matches [ 0 ] , ( size_t ) ( len + 1 ) , sizeof ( char * ) , ast_el_sort_compare ) ;
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 - - ;
continue ;
}
numoutput + + ; numoutputline + + ;
fprintf ( stdout , " %-*s " , max , matches [ idx ] ) ;
}
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
{
2003-02-06 06:15:25 +00:00
int len = 0 ;
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 ;
if ( option_remote ) {
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 ;
/* Start with a 2048 byte buffer */
mbuf = malloc ( maxmbuf ) ;
if ( ! mbuf )
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 */
maxmbuf + = 1024 ;
mbuf = realloc ( mbuf , maxmbuf ) ;
if ( ! mbuf )
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 ;
} else {
nummatches = ast_cli_generatornummatches ( ( char * ) lf - > buffer , ptr ) ;
matches = ast_cli_completion_matches ( ( char * ) lf - > buffer , ptr ) ;
}
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 ;
}
}
2003-04-08 13:45:36 +00:00
free ( matches ) ;
2003-02-06 06:15:25 +00:00
}
return ( char * ) retval ;
}
static int ast_el_initialize ( void )
{
HistEvent ev ;
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 ) ;
el_set ( el , EL_EDITOR , " emacs " ) ;
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 ;
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 ] ;
2003-02-06 06:15:25 +00:00
char * stringp = NULL ;
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 ) ;
stringp = buf ;
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> " ;
2003-02-06 06:15:25 +00:00
stringp = hostname ;
strsep ( & stringp , " . " ) ;
2001-05-09 03:11:22 +00:00
if ( cpid )
pid = atoi ( cpid ) ;
else
pid = - 1 ;
snprintf ( tmp , sizeof ( tmp ) , " set verbose atleast %d " , option_verbose ) ;
fdprint ( ast_consock , tmp ) ;
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 ) ;
2001-05-09 03:11:22 +00:00
if ( strlen ( filename ) )
2003-02-06 06:15:25 +00:00
ast_el_read_history ( filename ) ;
2002-05-14 14:43:52 +00:00
ast_cli_register ( & quit ) ;
2003-02-06 06:15:25 +00:00
ast_cli_register ( & astexit ) ;
2002-05-14 14:43:52 +00:00
#if 0
ast_cli_register ( & astshutdown ) ;
# endif
2003-06-23 16:40:12 +00:00
if ( option_exec & & data ) { /* hack to print output then exit if asterisk -rx is used */
char tempchar ;
ast_el_read_char ( el , & tempchar ) ;
return ;
}
2001-05-09 03:11:22 +00:00
for ( ; ; ) {
2003-02-06 06:15:25 +00:00
ebuf = ( char * ) el_gets ( el , & num ) ;
if ( ebuf & & strlen ( ebuf ) ) {
if ( ebuf [ strlen ( ebuf ) - 1 ] = = ' \n ' )
ebuf [ strlen ( ebuf ) - 1 ] = ' \0 ' ;
if ( ! remoteconsolehandler ( ebuf ) ) {
res = write ( ast_consock , ebuf , strlen ( ebuf ) + 1 ) ;
2001-05-09 03:11:22 +00:00
if ( res < 1 ) {
ast_log ( LOG_WARNING , " Unable to write: %s \n " , strerror ( errno ) ) ;
break ;
}
}
}
}
printf ( " \n Disconnected from Asterisk server \n " ) ;
}
2003-02-06 06:15:25 +00:00
static int show_cli_help ( void ) {
2002-09-12 03:22:07 +00:00
printf ( " Asterisk " ASTERISK_VERSION " , Copyright (C) 2000-2002, Digium. \n " ) ;
printf ( " Usage: asterisk [OPTIONS] \n " ) ;
printf ( " Valid Options: \n " ) ;
printf ( " -h This help screen \n " ) ;
printf ( " -r Connect to Asterisk on this machine \n " ) ;
printf ( " -f Do not fork \n " ) ;
printf ( " -n Disable console colorization \n " ) ;
printf ( " -p Run as pseudo-realtime thread \n " ) ;
printf ( " -v Increase verbosity (multiple v's = more verbose) \n " ) ;
printf ( " -q Quiet mode (supress output) \n " ) ;
2003-02-06 06:15:25 +00:00
printf ( " -g Dump core in case of a crash \n " ) ;
2002-09-12 03:22:07 +00:00
printf ( " -x <cmd> Execute command <cmd> (only valid with -r) \n " ) ;
printf ( " -i Initializie crypto keys at startup \n " ) ;
printf ( " -c Provide console CLI \n " ) ;
printf ( " -d Enable extra debugging \n " ) ;
printf ( " \n " ) ;
return 0 ;
}
2003-03-16 22:37:31 +00:00
static void ast_readconfig ( void ) {
2003-02-06 06:15:25 +00:00
struct ast_config * cfg ;
struct ast_variable * v ;
char * config = ASTCONFPATH ;
if ( option_overrideconfig = = 1 ) {
cfg = ast_load ( ( char * ) ast_config_AST_CONFIG_FILE ) ;
} else {
cfg = ast_load ( config ) ;
}
/* init with buildtime config */
strncpy ( ( char * ) ast_config_AST_CONFIG_DIR , AST_CONFIG_DIR , sizeof ( ast_config_AST_CONFIG_DIR ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_SPOOL_DIR , AST_SPOOL_DIR , sizeof ( ast_config_AST_SPOOL_DIR ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_MODULE_DIR , AST_MODULE_DIR , sizeof ( ast_config_AST_VAR_DIR ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_VAR_DIR , AST_VAR_DIR , sizeof ( ast_config_AST_VAR_DIR ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_LOG_DIR , AST_LOG_DIR , sizeof ( ast_config_AST_LOG_DIR ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_AGI_DIR , AST_AGI_DIR , sizeof ( ast_config_AST_AGI_DIR ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_DB , AST_DB , sizeof ( ast_config_AST_DB ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_KEY_DIR , AST_KEY_DIR , sizeof ( ast_config_AST_KEY_DIR ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_PID , AST_PID , sizeof ( ast_config_AST_PID ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_SOCKET , AST_SOCKET , sizeof ( ast_config_AST_SOCKET ) - 1 ) ;
strncpy ( ( char * ) ast_config_AST_RUN_DIR , AST_RUN_DIR , sizeof ( ast_config_AST_RUN_DIR ) - 1 ) ;
/* no asterisk.conf? no problem, use buildtime config! */
if ( ! cfg ) {
return ;
}
v = ast_variable_browse ( cfg , " directories " ) ;
while ( v ) {
if ( ! strcasecmp ( v - > name , " astetcdir " ) ) {
strncpy ( ( char * ) ast_config_AST_CONFIG_DIR , v - > value , sizeof ( ast_config_AST_CONFIG_DIR ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " astspooldir " ) ) {
strncpy ( ( char * ) ast_config_AST_SPOOL_DIR , v - > value , sizeof ( ast_config_AST_SPOOL_DIR ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " astvarlibdir " ) ) {
strncpy ( ( char * ) ast_config_AST_VAR_DIR , v - > value , sizeof ( ast_config_AST_VAR_DIR ) - 1 ) ;
snprintf ( ( char * ) ast_config_AST_DB , sizeof ( ast_config_AST_DB ) - 1 , " %s/%s " , v - > value , " astdb " ) ;
} else if ( ! strcasecmp ( v - > name , " astlogdir " ) ) {
strncpy ( ( char * ) ast_config_AST_LOG_DIR , v - > value , sizeof ( ast_config_AST_LOG_DIR ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " astagidir " ) ) {
strncpy ( ( char * ) ast_config_AST_AGI_DIR , v - > value , sizeof ( ast_config_AST_AGI_DIR ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " astrundir " ) ) {
snprintf ( ( char * ) ast_config_AST_PID , sizeof ( ast_config_AST_PID ) - 1 , " %s/%s " , v - > value , " asterisk.pid " ) ;
snprintf ( ( char * ) ast_config_AST_SOCKET , sizeof ( ast_config_AST_SOCKET ) - 1 , " %s/%s " , v - > value , " asterisk.ctl " ) ;
strncpy ( ( char * ) ast_config_AST_RUN_DIR , v - > value , sizeof ( ast_config_AST_RUN_DIR ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " astmoddir " ) ) {
strncpy ( ( char * ) ast_config_AST_MODULE_DIR , v - > value , sizeof ( ast_config_AST_MODULE_DIR ) - 1 ) ;
}
v = v - > next ;
}
ast_destroy ( cfg ) ;
}
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 ] = " " ;
2001-03-22 04:14:04 +00:00
char hostname [ 256 ] ;
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 ;
char * buf ;
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 ) {
fprintf ( stderr , " Truncating argument size to %d \n " , sizeof ( _argv ) / sizeof ( _argv [ 0 ] ) - 1 ) ;
argc = sizeof ( _argv ) / sizeof ( _argv [ 0 ] ) - 1 ;
}
for ( x = 0 ; x < argc ; x + + )
_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 */
if ( argv [ 0 ] & & ( strstr ( argv [ 0 ] , " rasterisk " ) ) ! = NULL ) {
option_remote + + ;
option_nofork + + ;
}
2001-03-22 04:14:04 +00:00
if ( gethostname ( hostname , sizeof ( hostname ) ) )
2001-12-25 21:12:07 +00:00
strncpy ( hostname , " <Unknown> " , sizeof ( hostname ) - 1 ) ;
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 ( ) ;
2001-12-25 21:12:07 +00:00
tdd_init ( ) ;
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 if we're root */
2003-02-06 06:15:25 +00:00
/*
1999-11-15 04:57:28 +00:00
if ( geteuid ( ) ) {
ast_log ( LOG_ERROR , " Must be run as root \n " ) ;
exit ( 1 ) ;
}
2003-02-06 06:15:25 +00:00
*/
1999-11-15 04:57:28 +00:00
/* Check for options */
2004-01-28 21:32:48 +00:00
while ( ( c = getopt ( argc , argv , " hfdvqprgcinx:C: " ) ) ! = - 1 ) {
1999-11-15 04:57:28 +00:00
switch ( c ) {
case ' d ' :
option_debug + + ;
option_nofork + + ;
1999-12-19 22:38:55 +00:00
break ;
2000-01-02 20:59:00 +00:00
case ' c ' :
option_console + + ;
option_nofork + + ;
2001-03-22 04:14:04 +00:00
break ;
2001-05-09 03:11:22 +00:00
case ' f ' :
option_nofork + + ;
break ;
2002-05-14 14:43:52 +00:00
case ' n ' :
option_nocolor + + ;
break ;
2001-05-09 03:11:22 +00:00
case ' r ' :
option_remote + + ;
option_nofork + + ;
break ;
1999-12-19 22:38:55 +00:00
case ' p ' :
option_highpriority + + ;
1999-11-15 04:57:28 +00:00
break ;
case ' v ' :
option_verbose + + ;
2000-01-02 20:59:00 +00:00
option_nofork + + ;
1999-11-15 04:57:28 +00:00
break ;
case ' q ' :
option_quiet + + ;
break ;
2001-05-09 03:11:22 +00:00
case ' x ' :
option_exec + + ;
xarg = optarg ;
break ;
2003-02-06 06:15:25 +00:00
case ' C ' :
strncpy ( ( char * ) ast_config_AST_CONFIG_FILE , optarg , sizeof ( ast_config_AST_CONFIG_FILE ) ) ;
option_overrideconfig + + ;
break ;
2001-12-25 21:12:07 +00:00
case ' i ' :
option_initcrypto + + ;
break ;
2003-02-06 06:15:25 +00:00
case ' g ' :
option_dumpcore + + ;
break ;
2002-09-12 03:22:07 +00:00
case ' h ' :
show_cli_help ( ) ;
exit ( 0 ) ;
1999-11-15 04:57:28 +00:00
case ' ? ' :
exit ( 1 ) ;
}
}
2002-05-14 14:43:52 +00:00
2003-02-06 06:15:25 +00:00
if ( option_dumpcore ) {
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 ) ) ;
}
}
2002-05-14 14:43:52 +00:00
term_init ( ) ;
printf ( term_end ( ) ) ;
fflush ( stdout ) ;
2003-02-06 06:15:25 +00:00
if ( option_console & & ! option_verbose )
ast_verbose ( " [ Reading Master Configuration ] " ) ;
ast_readconfig ( ) ;
2003-04-16 13:43:11 +00:00
if ( option_console ) {
if ( el_hist = = NULL | | el = = NULL )
ast_el_initialize ( ) ;
2003-02-06 06:15:25 +00:00
2003-04-16 13:43:11 +00:00
if ( strlen ( filename ) )
ast_el_read_history ( filename ) ;
}
2003-02-06 06:15:25 +00:00
2001-05-09 03:11:22 +00:00
if ( ast_tryconnect ( ) ) {
/* One is already running */
if ( option_remote ) {
if ( option_exec ) {
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_register_verbose ( console_verboser ) ;
2004-01-14 16:43:07 +00:00
ast_verbose ( " Asterisk " ASTERISK_VERSION " , Copyright (C) 1999-2004 Digium. \n " ) ;
ast_verbose ( " Written by Mark Spencer <markster@digium.com> \n " ) ;
2001-05-09 03:11:22 +00:00
ast_verbose ( " ========================================================================= \n " ) ;
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 {
2003-02-06 06:15:25 +00:00
ast_log ( LOG_ERROR , " Asterisk already running on %s. Use 'asterisk -r' to connect. \n " , ( char * ) 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 ) ;
}
} else if ( option_remote | | option_exec ) {
ast_log ( LOG_ERROR , " Unable to connect to remote asterisk \n " ) ;
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 */
2003-02-06 06:15:25 +00:00
unlink ( ( char * ) ast_config_AST_PID ) ;
f = fopen ( ( char * ) ast_config_AST_PID , " w " ) ;
2002-09-12 03:22:07 +00:00
if ( f ) {
fprintf ( f , " %d \n " , getpid ( ) ) ;
fclose ( f ) ;
} else
2003-02-06 06:15:25 +00:00
ast_log ( LOG_WARNING , " Unable to open pid file '%s': %s \n " , ( char * ) ast_config_AST_PID , strerror ( errno ) ) ;
2001-12-25 21:12:07 +00:00
if ( ! option_verbose & & ! option_debug & & ! option_nofork & & ! option_console ) {
2002-09-12 03:22:07 +00:00
daemon ( 0 , 0 ) ;
2003-10-16 10:27:41 +00:00
/* Blindly re-write pid file since we are forking */
unlink ( ( char * ) ast_config_AST_PID ) ;
f = fopen ( ( char * ) ast_config_AST_PID , " w " ) ;
if ( f ) {
fprintf ( f , " %d \n " , getpid ( ) ) ;
fclose ( f ) ;
} else
ast_log ( LOG_WARNING , " Unable to open pid file '%s': %s \n " , ( char * ) ast_config_AST_PID , strerror ( errno ) ) ;
2001-05-09 03:11:22 +00:00
}
2001-12-25 21:12:07 +00:00
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 ) ;
if ( option_console | | option_verbose | | option_remote )
ast_register_verbose ( console_verboser ) ;
1999-11-15 04:57:28 +00:00
/* Print a welcome message if desired */
2000-01-02 20:59:00 +00:00
if ( option_verbose | | option_console ) {
2001-05-09 03:11:22 +00:00
ast_verbose ( " Asterisk " ASTERISK_VERSION " , Copyright (C) 1999-2001 Linux Support Services, Inc. \n " ) ;
1999-11-15 04:57:28 +00:00
ast_verbose ( " Written by Mark Spencer <markster@linux-support.net> \n " ) ;
ast_verbose ( " ========================================================================= \n " ) ;
}
2000-01-02 20:59:00 +00:00
if ( option_console & & ! option_verbose )
ast_verbose ( " [ Booting... " ) ;
2003-09-16 19:35:57 +00:00
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 ) ;
2002-05-14 14:43:52 +00:00
if ( set_priority ( option_highpriority ) ) {
printf ( term_quit ( ) ) ;
2001-03-22 04:14:04 +00:00
exit ( 1 ) ;
2002-05-14 14:43:52 +00:00
}
if ( init_logger ( ) ) {
printf ( term_quit ( ) ) ;
1999-11-15 04:57:28 +00:00
exit ( 1 ) ;
2002-05-14 14:43:52 +00:00
}
2002-09-12 03:22:07 +00:00
if ( init_manager ( ) ) {
printf ( term_quit ( ) ) ;
exit ( 1 ) ;
}
2003-05-16 02:50:46 +00:00
ast_rtp_init ( ) ;
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
}
if ( load_pbx ( ) ) {
printf ( term_quit ( ) ) ;
1999-11-15 04:57:28 +00:00
exit ( 1 ) ;
2002-05-14 14:43:52 +00:00
}
if ( load_modules ( ) ) {
printf ( term_quit ( ) ) ;
1999-11-15 04:57:28 +00:00
exit ( 1 ) ;
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
}
2003-02-06 06:15:25 +00:00
if ( astdb_init ( ) ) {
printf ( term_quit ( ) ) ;
exit ( 1 ) ;
}
2003-05-01 04:29:25 +00:00
if ( ast_enum_init ( ) ) {
printf ( term_quit ( ) ) ;
exit ( 1 ) ;
}
1999-11-15 04:57:28 +00:00
/* We might have the option of showing a console, but for now just
do nothing . . . */
2000-01-02 20:59:00 +00:00
if ( option_console & & ! option_verbose )
ast_verbose ( " ] \n " ) ;
if ( option_verbose | | option_console )
2002-05-14 14:43:52 +00:00
ast_verbose ( term_color ( tmp , " Asterisk Ready. \n " , COLOR_BRWHITE , COLOR_BLACK , sizeof ( tmp ) ) ) ;
2004-03-02 23:50:03 +00:00
if ( option_nofork )
consolethread = pthread_self ( ) ;
2000-01-02 20:59:00 +00:00
fully_booted = 1 ;
2001-05-09 03:11:22 +00:00
pthread_sigmask ( SIG_UNBLOCK , & sigs , NULL ) ;
2003-04-28 19:58:43 +00:00
# ifdef __AST_DEBUG_MALLOC
__ast_mm_init ( ) ;
# endif
2003-05-02 15:37:34 +00:00
time ( & ast_startuptime ) ;
2002-05-14 14:43:52 +00:00
ast_cli_register ( & astshutdownnow ) ;
ast_cli_register ( & astshutdowngracefully ) ;
ast_cli_register ( & astrestartnow ) ;
ast_cli_register ( & astrestartgracefully ) ;
ast_cli_register ( & astrestartwhenconvenient ) ;
2003-04-23 16:24:09 +00:00
ast_cli_register ( & astshutdownwhenconvenient ) ;
2002-05-14 14:43:52 +00:00
ast_cli_register ( & aborthalt ) ;
2003-10-22 03:46:36 +00:00
ast_cli_register ( & astbang ) ;
2000-01-02 20:59:00 +00:00
if ( option_console ) {
/* Console stuff now... */
/* Register our quit function */
2000-10-25 23:22:50 +00:00
char title [ 256 ] ;
set_icon ( " Asterisk " ) ;
2004-03-20 21:13:12 +00:00
snprintf ( title , sizeof ( title ) , " Asterisk Console on '%s' (pid %d) " , hostname , ast_mainpid ) ;
2000-10-25 23:22:50 +00:00
set_title ( title ) ;
2000-01-02 20:59:00 +00:00
ast_cli_register ( & quit ) ;
2003-02-06 06:15:25 +00:00
ast_cli_register ( & astexit ) ;
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 ) ;
2003-08-21 02:34:03 +00:00
} else {
if ( option_remote )
ast_cli ( STDOUT_FILENO , " \n Use EXIT or QUIT to exit the asterisk console \n " ) ;
}
2003-02-06 06:15:25 +00:00
}
2000-01-02 20:59:00 +00:00
} else {
2001-12-25 21:12:07 +00:00
/* Do nothing */
2004-05-01 03:14:02 +00:00
for ( ; ; )
poll ( NULL , 0 , - 1 ) ;
2000-01-02 20:59:00 +00:00
}
1999-11-15 04:57:28 +00:00
return 0 ;
}
2004-04-22 00:20:34 +00:00
2004-04-28 13:53:01 +00:00
# if defined(__FreeBSD__)
/* duh? ERANGE value copied from web... */
# define ERANGE 34
# undef gethostbyname
int gethostbyname_r ( const char * name ,
struct hostent * ret ,
char * buf ,
size_t buflen ,
struct hostent * * result ,
int * h_errnop ) ;
int gethostbyname_r ( const char * name ,
struct hostent * ret ,
char * buf ,
size_t buflen ,
struct hostent * * result ,
int * h_errnop ) {
int hsave ;
struct hostent * ph ;
2004-04-28 19:55:04 +00:00
static ast_mutex_t __mutex = AST_MUTEX_INITIALIZER ;
ast_mutex_lock ( & __mutex ) ; /* begin critical area */
2004-04-28 13:53:01 +00:00
hsave = h_errno ;
ph = gethostbyname ( name ) ;
* h_errnop = h_errno ; /* copy h_errno to *h_herrnop */
if ( ph = = NULL ) {
* result = NULL ;
} else {
char * * p , * * q ;
char * pbuf ;
int nbytes = 0 ;
int naddr = 0 , naliases = 0 ;
/* determine if we have enough space in buf */
/* count how many addresses */
for ( p = ph - > h_addr_list ; * p ! = 0 ; p + + ) {
nbytes + = ph - > h_length ; /* addresses */
nbytes + = sizeof ( * p ) ; /* pointers */
naddr + + ;
}
nbytes + = sizeof ( * p ) ; /* one more for the terminating NULL */
/* count how many aliases, and total length of strings */
for ( p = ph - > h_aliases ; * p ! = 0 ; p + + ) {
nbytes + = ( strlen ( * p ) + 1 ) ; /* aliases */
nbytes + = sizeof ( * p ) ; /* pointers */
naliases + + ;
}
nbytes + = sizeof ( * p ) ; /* one more for the terminating NULL */
/* here nbytes is the number of bytes required in buffer */
/* as a terminator must be there, the minimum value is ph->h_length */
if ( nbytes > buflen ) {
* result = NULL ;
pthread_mutex_unlock ( & __mutex ) ; /* end critical area */
return ERANGE ; /* not enough space in buf!! */
}
/* There is enough space. Now we need to do a deep copy! */
/* Allocation in buffer:
from [ 0 ] to [ ( naddr - 1 ) * sizeof ( * p ) ] :
pointers to addresses
at [ naddr * sizeof ( * p ) ] :
NULL
from [ ( naddr + 1 ) * sizeof ( * p ) ] to [ ( naddr + naliases ) * sizeof ( * p ) ] :
pointers to aliases
at [ ( naddr + naliases + 1 ) * sizeof ( * p ) ] :
NULL
then naddr addresses ( fixed length ) , and naliases aliases ( asciiz ) .
*/
* ret = * ph ; /* copy whole structure (not its address!) */
/* copy addresses */
q = ( char * * ) buf ; /* pointer to pointers area (type: char **) */
ret - > h_addr_list = q ; /* update pointer to address list */
pbuf = buf + ( ( naddr + naliases + 2 ) * sizeof ( * p ) ) ; /* skip that area */
for ( p = ph - > h_addr_list ; * p ! = 0 ; p + + ) {
memcpy ( pbuf , * p , ph - > h_length ) ; /* copy address bytes */
* q + + = pbuf ; /* the pointer is the one inside buf... */
pbuf + = ph - > h_length ; /* advance pbuf */
}
* q + + = NULL ; /* address list terminator */
/* copy aliases */
ret - > h_aliases = q ; /* update pointer to aliases list */
for ( p = ph - > h_aliases ; * p ! = 0 ; p + + ) {
strcpy ( pbuf , * p ) ; /* copy alias strings */
* q + + = pbuf ; /* the pointer is the one inside buf... */
pbuf + = strlen ( * p ) ; /* advance pbuf */
* pbuf + + = 0 ; /* string terminator */
}
* q + + = NULL ; /* terminator */
strcpy ( pbuf , ph - > h_name ) ; /* copy alias strings */
ret - > h_name = pbuf ;
pbuf + = strlen ( ph - > h_name ) ; /* advance pbuf */
* pbuf + + = 0 ; /* string terminator */
* result = ret ; /* and let *result point to structure */
}
h_errno = hsave ; /* restore h_errno */
2004-04-28 19:55:04 +00:00
ast_mutex_unlock ( & __mutex ) ; /* end critical area */
2004-04-28 13:53:01 +00:00
2004-04-28 19:55:04 +00:00
return ( * result ! = NULL ) ;
2004-04-28 13:53:01 +00:00
}
# endif
2004-04-22 00:20:34 +00:00
struct hostent * ast_gethostbyname ( const char * host , struct ast_hostent * hp )
{
int res ;
2004-04-22 05:11:11 +00:00
int herrno ;
2004-04-22 00:20:34 +00:00
struct hostent * result = NULL ;
2004-04-28 13:53:01 +00:00
2004-04-22 05:11:11 +00:00
res = gethostbyname_r ( host , & hp - > hp , hp - > buf , sizeof ( hp - > buf ) , & result , & herrno ) ;
2004-04-28 13:53:01 +00:00
2004-04-22 00:20:34 +00:00
if ( res )
return NULL ;
return & hp - > hp ;
}