Newer
Older
* Asterisk -- An open source telephony toolkit.
* Copyright (C) 1999 - 2005, Digium, Inc.
* Mark Spencer <markster@digium.com>
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* 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.
*/
/*
*
* Top level source file for asterisk
*
*/
#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.h"
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"
Kevin P. Fleming
committed
#include "asterisk/version.h"
#include "asterisk/build.h"
#include "asterisk/linkedlists.h"
Kevin P. Fleming
committed
#include "asterisk/devicestate.h"
Kevin P. Fleming
committed
#include "defaults.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;
Kevin P. Fleming
committed
int option_priority_jumping = 1;
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];
Kevin P. Fleming
committed
char ast_config_AST_MONITOR_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];
char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
static char *_argv[256];
static int shuttingdown = 0;
static int restartnow = 0;
static pthread_t consolethread = AST_PTHREADT_NULL;
#if !defined(LOW_MEMORY)
struct file_version {
AST_LIST_ENTRY(file_version) list;
Kevin P. Fleming
committed
const char *file;
char *version;
};
static AST_LIST_HEAD_STATIC(file_versions, file_version);
void ast_register_file_version(const char *file, const char *version)
{
struct file_version *new;
Kevin P. Fleming
committed
char *work;
size_t version_length;
Kevin P. Fleming
committed
work = ast_strdupa(version);
work = ast_strip(ast_strip_quoted(work, "$", "$"));
version_length = strlen(work) + 1;
new = calloc(1, sizeof(*new) + version_length);
if (!new)
return;
new->file = file;
Kevin P. Fleming
committed
new->version = (char *) new + sizeof(*new);
memcpy(new->version, work, version_length);
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);
Kevin P. Fleming
committed
if (find)
free(find);
}
static char show_version_files_help[] =
"Usage: show version files [like <pattern>]\n"
" Shows the revision numbers of the files used to build this copy of Asterisk.\n"
" Optional regular expression pattern is used to filter the file list.\n";
static int handle_show_version_files(int fd, int argc, char *argv[])
{
#define FORMAT "%-25.25s %-40.40s\n"
struct file_version *iterator;
Kevin P. Fleming
committed
regex_t regexbuf;
int havepattern = 0;
Kevin P. Fleming
committed
int count_files = 0;
Kevin P. Fleming
committed
switch (argc) {
case 5:
if (!strcasecmp(argv[3], "like")) {
if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
return RESULT_SHOWUSAGE;
havepattern = 1;
} else
return RESULT_SHOWUSAGE;
break;
case 4:
havename = 1;
break;
Kevin P. Fleming
committed
case 3:
break;
default:
return RESULT_SHOWUSAGE;
}
Kevin P. Fleming
committed
ast_cli(fd, FORMAT, "File", "Revision");
ast_cli(fd, FORMAT, "----", "--------");
AST_LIST_LOCK(&file_versions);
AST_LIST_TRAVERSE(&file_versions, iterator, list) {
if (havename && strcasecmp(iterator->file, argv[3]))
continue;
Kevin P. Fleming
committed
if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
continue;
ast_cli(fd, FORMAT, iterator->file, iterator->version);
Kevin P. Fleming
committed
count_files++;
}
AST_LIST_UNLOCK(&file_versions);
Kevin P. Fleming
committed
if (!havename) {
ast_cli(fd, "%d files listed.\n", count_files);
}
Kevin P. Fleming
committed
if (havepattern)
regfree(®exbuf);
Kevin P. Fleming
committed
#undef FORMAT
}
static char *complete_show_version_files(char *line, char *word, int pos, int state)
{
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) {
if (!strncasecmp(word, find->file, matchlen)) {
if (++which > state) {
ret = strdup(find->file);
break;
}
}
}
AST_LIST_UNLOCK(&file_versions);
return ret;
}
#endif /* ! LOW_MEMORY */
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)
{
}
AST_MUTEX_DEFINE_STATIC(safe_system_lock);
static unsigned int safe_system_level = 0;
static void *safe_system_prev_handler;
Mark Spencer
committed
int ast_safe_system(const char *s)
{
pid_t pid;
int x;
int res;
struct rusage rusage;
int status;
unsigned int level;
/* keep track of how many ast_safe_system() functions
are running at this moment
*/
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);
Mark Spencer
committed
pid = fork();
Mark Spencer
committed
if (pid == 0) {
/* Close file descriptors and launch system command */
for (x = STDERR_FILENO + 1; x < 4096; x++)
Mark Spencer
committed
close(x);
execl("/bin/sh", "/bin/sh", "-c", s, NULL);
Mark Spencer
committed
} else if (pid > 0) {
for(;;) {
res = wait4(pid, &status, 0, &rusage);
if (res > -1) {
res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
break;
} else if (errno != EINTR)
Mark Spencer
committed
}
} else {
ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
res = -1;
}
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);
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))
ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
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[0].revents = 0;
fds[1].fd = con->p[0];
fds[1].events = POLLIN;
fds[1].revents = 0;
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;
uid_t uid = -1;
gid_t gid = -1;
for (x = 0; x < AST_MAX_CONNECTS; x++)
unlink(ast_config_AST_SOCKET);
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;
ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", 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", 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);
if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
} else {
uid = pw->pw_uid;
}
if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_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 (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
sscanf(ast_config_AST_CTL_PERMISSIONS, "%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;
ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
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 */
Kevin P. Fleming
committed
/* SLD: seems to be some pthread activity relating to the printf anyway:
* which is leading to a deadlock? */
#if 0
if (option_debug > 2)
printf("-- Asterisk Urgent handler\n");
Kevin P. Fleming
committed
#endif
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);
Kevin P. Fleming
committed
signal(num, hup_handler);
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");
Kevin P. Fleming
committed
signal(sig, child_handler);
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);
}
Kevin P. Fleming
committed
int ast_set_priority(int pri)
/* 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();
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
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) && (consolethread != pthread_self())) {
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[] =