Newer
Older
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Top level source file for asterisk
*
* Copyright (C) 1999 - 2005, Digium, Inc.
* Mark Spencer <markster@digium.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#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>
#if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
#include <netdb.h>
#endif
Kevin P. Fleming
committed
#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/module.h"
#include "asterisk/image.h"
#include "asterisk/tdd.h"
#include "asterisk/term.h"
#include "asterisk/manager.h"
#include "asterisk/cdr.h"
Kevin P. Fleming
committed
#include "asterisk/pbx.h"
#include "asterisk/enum.h"
#include "asterisk/rtp.h"
#include "asterisk/app.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/io.h"
#include "asterisk/lock.h"
Kevin P. Fleming
committed
#include "asterisk/config.h"
Mark Spencer
committed
#ifndef AF_LOCAL
#define AF_LOCAL AF_UNIX
#define PF_LOCAL PF_UNIX
#endif
#define AST_MAX_CONNECTS 128
#define NUM_MSGS 64
#define WELCOME_MESSAGE ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005 Digium.\n"); \
ast_verbose( "Written by Mark Spencer <markster@digium.com>\n"); \
ast_verbose( "=========================================================================\n")
int option_exec_includes=0;
int option_cache_record_files = 0;
int option_timestamp = 0;
int option_reconnect = 0;
int option_transcode_slin = 1;
Russell Bryant
committed
int option_dontwarn = 0;
char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
char debug_filename[AST_FILENAME_MAX] = "";
static int ast_socket = -1; /* UNIX Socket for allowing remote control */
static int ast_consock = -1; /* UNIX Socket for controlling another asterisk */
Mark Spencer
committed
int ast_mainpid;
struct console {
int fd; /* File descriptor */
int p[2]; /* Pipe */
pthread_t t; /* Thread of handler */
};
static struct ast_atexit {
void (*func)(void);
struct ast_atexit *next;
} *atexits = NULL;
AST_MUTEX_DEFINE_STATIC(atexitslock);
static History *el_hist = NULL;
static EditLine *el = NULL;
static char *remotehostname;
char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
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];
static char *_argv[256];
static int shuttingdown = 0;
static int restartnow = 0;
static pthread_t consolethread = AST_PTHREADT_NULL;
int ast_register_atexit(void (*func)(void))
{
int res = -1;
struct ast_atexit *ae;
ast_unregister_atexit(func);
ae = malloc(sizeof(struct ast_atexit));
ast_mutex_lock(&atexitslock);
if (ae) {
memset(ae, 0, sizeof(struct ast_atexit));
ae->next = atexits;
ae->func = func;
atexits = ae;
res = 0;
}
ast_mutex_unlock(&atexitslock);
return res;
}
void ast_unregister_atexit(void (*func)(void))
{
struct ast_atexit *ae, *prev = NULL;
ast_mutex_lock(&atexitslock);
ae = atexits;
while(ae) {
if (ae->func == func) {
if (prev)
prev->next = ae->next;
else
atexits = ae->next;
break;
}
prev = ae;
ae = ae->next;
}
ast_mutex_unlock(&atexitslock);
}
static int fdprint(int fd, const char *s)
{
return write(fd, s, strlen(s) + 1);
}
/* NULL handler so we can collect the child exit status */
static void null_sig_handler(int signal)
{
}
Mark Spencer
committed
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;
void (*prev_handler) = signal(SIGCHLD, null_sig_handler);
Mark Spencer
committed
pid = fork();
if (pid == 0) {
/* Close file descriptors and launch system command */
for (x=STDERR_FILENO + 1; x<4096;x++) {
close(x);
}
res = execl("/bin/sh", "/bin/sh", "-c", s, NULL);
exit(1);
Mark Spencer
committed
} else if (pid > 0) {
for(;;) {
res = wait4(pid, &status, 0, &rusage);
if (res > -1) {
if (WIFEXITED(status))
res = WEXITSTATUS(status);
else
res = -1;
Mark Spencer
committed
} else {
if (errno != EINTR)
break;
}
}
} else {
ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
res = -1;
}
Mark Spencer
committed
return res;
}
/*
* 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);
static void network_verboser(const char *s, int pos, int replace, int complete)
if (replace) {
char *t = alloca(strlen(s) + 2);
if (t) {
sprintf(t, "\r%s", s);
if (complete)
ast_network_puts(t);
} else {
ast_log(LOG_ERROR, "Out of memory\n");
ast_network_puts(s);
}
} else {
if (complete)
ast_network_puts(s);
}
static pthread_t lthread;
static void *netconsole(void *vconsole)
{
struct console *con = vconsole;
char hostname[MAXHOSTNAMELEN]="";
struct pollfd fds[2];
if (gethostname(hostname, sizeof(hostname)-1))
strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
Mark Spencer
committed
snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
fds[0].fd = con->fd;
fds[0].events = POLLIN;
fds[1].fd = con->p[0];
fds[1].events = POLLIN;
res = poll(fds, 2, -1);
if (errno != EINTR)
ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
if (fds[0].revents) {
tmp[res] = 0;
ast_cli_command(con->fd, tmp);
}
if (fds[1].revents) {
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 sunaddr;
socklen_t len;
struct pollfd fds[1];
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
for(;;) {
fds[0].fd = ast_socket;
fds[0].events= POLLIN;
s = poll(fds, 1, -1);
ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
len = sizeof(sunaddr);
s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
} else {
for (x=0;x<AST_MAX_CONNECTS;x++) {
if (consoles[x].fd < 0) {
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
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;
}
flags = fcntl(consoles[x].p[1], F_GETFL);
fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
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 sunaddr;
struct ast_config *cfg;
char *config = ASTCONFPATH;
char *owner;
char *group;
char *perms;
uid_t uid;
gid_t gid;
for (x=0;x<AST_MAX_CONNECTS;x++)
consoles[x].fd = -1;
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(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_LOCAL;
strncpy(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path)-1);
res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
close(ast_socket);
ast_socket = -1;
return -1;
}
res = listen(ast_socket, 2);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
close(ast_socket);
ast_socket = -1;
return -1;
}
ast_register_verbose(network_verboser);
ast_pthread_create(<hread, NULL, listener, NULL);
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
/* Load the options for owner, group and permissions from
asterisk.conf. if the file doesn't exist (????) just skip
this part.
*/
if (option_overrideconfig == 1) {
cfg = ast_config_load((char *)ast_config_AST_CONFIG_FILE);
} else {
cfg = ast_config_load(config);
}
if (!cfg) return 0;
gid=-1;
uid=-1;
group = ast_variable_retrieve(cfg, "files", "astctlgroup");
owner = ast_variable_retrieve(cfg, "files", "astctlowner");
perms = ast_variable_retrieve(cfg, "files", "astctlpermissions");
if (owner!=NULL) {
struct passwd *pw;
if ((pw=getpwnam(owner))==NULL)
ast_log(LOG_WARNING, "Unable to find uid of user %s\n", owner);
else
uid=pw->pw_uid;
}
if (group!=NULL) {
struct group *grp;
if ((grp=getgrnam(group))==NULL)
ast_log(LOG_WARNING, "Unable to find gid of group %s\n", group);
else
gid=grp->gr_gid;
}
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 (perms!=NULL) {
mode_t p;
sscanf(perms, "%o", (int *) &p);
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));
}
return 0;
}
static int ast_tryconnect(void)
{
struct sockaddr_un sunaddr;
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(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_LOCAL;
strncpy(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path)-1);
res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
if (res) {
close(ast_consock);
ast_consock = -1;
return 0;
} else
return 1;
}
/* Called by soft_hangup to interrupt the poll, read, or other
system call. We don't actually need to do anything though. */
/* Cannot EVER ast_log from within a signal handler */
printf("Urgent handler\n");
static void hup_handler(int num)
{
if (option_verbose > 1)
printf("Received HUP signal -- Reloading configs\n");
if (restartnow)
execvp(_argv[0], _argv);
/* XXX This could deadlock XXX */
Mark Spencer
committed
ast_module_reload(NULL);
static void child_handler(int sig)
/* Must not ever ast_log or ast_verbose within signal handler */
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)
printf("Huh? Child handler, but nobody there?\n");
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);
}
static int set_priority(int pri)
{
struct sched_param sched;
/* 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. */
sched.sched_priority = 10;
if (sched_setscheduler(0, SCHED_RR, &sched)) {
ast_log(LOG_WARNING, "Unable to set high priority\n");
return -1;
} else
if (option_verbose)
ast_verbose("Set to realtime thread\n");
} else {
sched.sched_priority = 0;
if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
ast_log(LOG_WARNING, "Unable to set normal priority\n");
return -1;
}
}
#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
static void ast_run_atexits(void)
{
struct ast_atexit *ae;
ast_mutex_lock(&atexitslock);
ae = atexits;
while(ae) {
if (ae->func)
ae->func();
ae = ae->next;
}
ast_mutex_unlock(&atexitslock);
}
static void quit_handler(int num, int nice, int safeshutdown, int restart)
/* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
ast_cdr_engine_term();
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
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;
}
}
if (option_console || option_remote) {
if (getenv("HOME"))
snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
ast_el_write_history(filename);
if (el != NULL)
el_end(el);
if (el_hist != NULL)
history_end(el_hist);
if (option_verbose)
ast_verbose("Executing last minute cleanups\n");
ast_run_atexits();
ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
else if (option_debug)
ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
if (ast_consock > -1)
close(ast_consock);
if (ast_socket > -1)
if (!option_remote) unlink((char *)ast_config_AST_PID);
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");
restartnow = 1;
/* close logger */
close_logger();
/* If there is a consolethread running send it a SIGHUP
so it can execvp, otherwise we can do it ourselves */
if (consolethread != AST_PTHREADT_NULL) {
pthread_kill(consolethread, SIGHUP);
/* Give the signal handler some time to complete */
sleep(2);
} else
execvp(_argv[0], _argv);
} else {
/* close logger */
close_logger();
}
exit(0);
}
static void __quit_handler(int num)
{
quit_handler(num, 0, 1, 0);
static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
const char *c;
if (!strncmp(s, cmp, strlen(cmp))) {
c = s + strlen(cmp);
static void console_verboser(const char *s, int pos, int replace, int complete)
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)))
if (c)
fputs(c + pos,stdout);
else
fputs(s + pos,stdout);
if (complete) {
/* Wake up a poll()ing console */
if (option_console && consolethread != AST_PTHREADT_NULL)
static int ast_all_zeros(char *s)
{
while(*s) {
if (*s > 32)
return 0;
s++;
}
return 1;
}
if (s && !ast_all_zeros(s))
/* Give the console access to the shell */
if (s) {
Mark Spencer
committed
ast_safe_system(s+1);
Mark Spencer
committed
ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
} else
fprintf(stdout, "\nUse \"quit\" to exit\n");
Mark Spencer
committed
if (s && !ast_all_zeros(s))
/* Give the console access to the shell */
if (s) {
Mark Spencer
committed
ast_safe_system(s+1);
Mark Spencer
committed
ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
(s[4] == '\0' || isspace(s[4]))) {
} else
fprintf(stdout, "\nUse \"quit\" to exit\n");
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[] =
" Shuts down a running Asterisk immediately, hanging up all active calls .\n";
static char shutdown_gracefully_help[] =
" Causes Asterisk to not accept new calls, and exit when all\n"
" active calls have terminated normally.\n";
static char shutdown_when_convenient_help[] =
"Usage: stop when convenient\n"
" Causes Asterisk to perform a shutdown when all active calls have ended.\n";
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";
static char bang_help[] =
"Usage: !<command>\n"
" Executes a given shell command\n";
static int handle_quit(int fd, int argc, char *argv[])
{
if (argc != 1)
return RESULT_SHOWUSAGE;
quit_handler(0, 0, 1, 0);
return RESULT_SUCCESS;
}
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;
}
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;
}
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
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;
static int handle_bang(int fd, int argc, char *argv[])
{
return RESULT_SUCCESS;
}
Kevin P. Fleming
committed
static struct ast_cli_entry core_cli[] = {
{ { "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 },
{ { "!", NULL }, handle_bang,
"Execute a shell command", bang_help },
};
static int ast_el_read_char(EditLine *el, char *cp)
{
struct pollfd fds[2];
int res;
int max;
char buf[512];
for (;;) {
max = 1;
fds[0].fd = ast_consock;
fds[0].events = POLLIN;
fds[1].fd = STDIN_FILENO;
fds[1].events = POLLIN;
max++;
res = poll(fds, max, -1);
if (res < 0) {
if (errno == EINTR)
continue;
ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
if (!option_exec && fds[1].revents) {
num_read = read(STDIN_FILENO, cp, 1);
if (num_read < 1) {
break;
} else
return (num_read);
}
if (fds[0].revents) {
res = read(ast_consock, buf, sizeof(buf) - 1);
/* if the remote side disappears exit */
if (res < 1) {
fprintf(stderr, "\nDisconnected from Asterisk server\n");
if (!option_reconnect) {
quit_handler(0, 0, 0, 0);
} else {
int tries;
int reconnects_per_second = 20;
fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
for (tries=0;tries<30 * reconnects_per_second;tries++) {
if (ast_tryconnect()) {
fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
printf(term_quit());
break;
} else {
usleep(1000000 / reconnects_per_second);
}
}
fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
quit_handler(0, 0, 0, 0);
}
}