From 8b0c007ad990aa27d9868da49215fd1076ac77cc Mon Sep 17 00:00:00 2001 From: kpfleming Date: Mon, 21 Aug 2006 02:11:39 +0000 Subject: merge new_loader_completion branch, including (at least): - restructured build tree and makefiles to eliminate recursion problems - support for embedded modules - support for static builds - simpler cross-compilation support - simpler module/loader interface (no exported symbols) git-svn-id: http://svn.digium.com/svn/asterisk/trunk@40722 f38db490-d61c-443f-a65b-d21fe96a405b --- asterisk.c | 2724 ------------------------------------------------------------ 1 file changed, 2724 deletions(-) delete mode 100644 asterisk.c (limited to 'asterisk.c') diff --git a/asterisk.c b/asterisk.c deleted file mode 100644 index b523bfb0d..000000000 --- a/asterisk.c +++ /dev/null @@ -1,2724 +0,0 @@ -/* - * Asterisk -- An open source telephony toolkit. - * - * Copyright (C) 1999 - 2006, Digium, Inc. - * - * Mark Spencer - * - * 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. - */ - - -/* Doxygenified Copyright Header */ -/*! - * \mainpage Asterisk -- An Open Source Telephony Toolkit - * - * \par Developer Documentation for Asterisk - * This is the main developer documentation for Asterisk. It is - * generated by running "make progdocs". - * \par Additional documentation - * \arg \ref DevDoc - * \arg \ref ConfigFiles - * - * \section copyright Copyright and author - * - * Copyright (C) 1999 - 2006, Digium, Inc. - * Asterisk is a trade mark registered by Digium, Inc. - * - * \author Mark Spencer - * Also see \ref AstCREDITS - * - * \section license License - * See http://www.asterisk.org for more information about - * the Asterisk project. Please do not directly contact - * any of the maintainers of this project for assistance; - * the project provides a web site, mailing lists and IRC - * channels for your use. - * - * This program is free software, distributed under the terms of - * the GNU General Public License Version 2. See the LICENSE file - * at the top of the source tree. - * - * \verbinclude LICENSE - * - */ - -/*! \file - \brief Top level source file for Asterisk - the Open Source PBX. Implementation - of PBX core functions and CLI interface. - - */ - -#include "asterisk.h" - -ASTERISK_FILE_VERSION(__FILE__, "$Revision$") - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef linux -#include -#endif -#include - -#ifdef linux -#include -#endif - -#if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS) -#include -#if defined(SOLARIS) -int daemon(int, int); /* defined in libresolv of all places */ -#endif -#endif - -#include "asterisk/logger.h" -#include "asterisk/options.h" -#include "asterisk/cli.h" -#include "asterisk/channel.h" -#include "asterisk/ulaw.h" -#include "asterisk/alaw.h" -#include "asterisk/callerid.h" -#include "asterisk/image.h" -#include "asterisk/tdd.h" -#include "asterisk/term.h" -#include "asterisk/manager.h" -#include "asterisk/cdr.h" -#include "asterisk/pbx.h" -#include "asterisk/enum.h" -#include "asterisk/rtp.h" -#include "asterisk/http.h" -#include "asterisk/udptl.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" -#include "editline/histedit.h" -#include "asterisk/config.h" -#include "asterisk/version.h" -#include "asterisk/linkedlists.h" -#include "asterisk/devicestate.h" - -#include "asterisk/doxyref.h" /* Doxygen documentation */ - -#include "defaults.h" - -#ifndef AF_LOCAL -#define AF_LOCAL AF_UNIX -#define PF_LOCAL PF_UNIX -#endif - -#define AST_MAX_CONNECTS 128 -#define NUM_MSGS 64 - -/*! \brief Welcome message when starting a CLI interface */ -#define WELCOME_MESSAGE \ - ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \ - ast_verbose("Created by Mark Spencer \n"); \ - ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \ - ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \ - ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \ - ast_verbose("certain conditions. Type 'show license' for details.\n"); \ - ast_verbose("=========================================================================\n") - -/*! \defgroup main_options - \brief Main configuration options from \ref Config_ast "asterisk.conf" or - the operating system command line when starting Asterisk - Some of them can be changed in the CLI - */ -/*! @{ */ - -extern int ast_language_is_prefix; /* XXX move to some header */ - -struct ast_flags ast_options = { AST_DEFAULT_OPTIONS }; - -int option_verbose = 0; /*!< Verbosity level */ -int option_debug = 0; /*!< Debug level */ - -double option_maxload = 0.0; /*!< Max load avg on system */ -int option_maxcalls = 0; /*!< Max number of active calls */ - -/*! @} */ - -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 */ -pid_t ast_mainpid; -struct console { - int fd; /*!< File descriptor */ - int p[2]; /*!< Pipe */ - pthread_t t; /*!< Thread of handler */ - int mute; /*!< Is the console muted for logs */ -}; - -struct ast_atexit { - void (*func)(void); - AST_LIST_ENTRY(ast_atexit) list; -}; - -static AST_LIST_HEAD_STATIC(atexits, ast_atexit); - -time_t ast_startuptime; -time_t ast_lastreloadtime; - -static History *el_hist = NULL; -static EditLine *el = NULL; -static char *remotehostname; - -struct console consoles[AST_MAX_CONNECTS]; - -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[PATH_MAX]; -char ast_config_AST_CONFIG_FILE[PATH_MAX]; -char ast_config_AST_MODULE_DIR[PATH_MAX]; -char ast_config_AST_SPOOL_DIR[PATH_MAX]; -char ast_config_AST_MONITOR_DIR[PATH_MAX]; -char ast_config_AST_VAR_DIR[PATH_MAX]; -char ast_config_AST_DATA_DIR[PATH_MAX]; -char ast_config_AST_LOG_DIR[PATH_MAX]; -char ast_config_AST_AGI_DIR[PATH_MAX]; -char ast_config_AST_DB[PATH_MAX]; -char ast_config_AST_KEY_DIR[PATH_MAX]; -char ast_config_AST_PID[PATH_MAX]; -char ast_config_AST_SOCKET[PATH_MAX]; -char ast_config_AST_RUN_DIR[PATH_MAX]; -char ast_config_AST_RUN_USER[PATH_MAX]; -char ast_config_AST_RUN_GROUP[PATH_MAX]; -char ast_config_AST_CTL_PERMISSIONS[PATH_MAX]; -char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0"; -char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0"; -char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl"; -char ast_config_AST_SYSTEM_NAME[20] = ""; - -extern const char *ast_build_hostname; -extern const char *ast_build_kernel; -extern const char *ast_build_machine; -extern const char *ast_build_os; -extern const char *ast_build_date; -extern const char *ast_build_user; - -static char *_argv[256]; -static int shuttingdown = 0; -static int restartnow = 0; -static pthread_t consolethread = AST_PTHREADT_NULL; - -static char randompool[256]; - -#if !defined(LOW_MEMORY) -struct file_version { - AST_LIST_ENTRY(file_version) list; - 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; - char *work; - size_t version_length; - - work = ast_strdupa(version); - work = ast_strip(ast_strip_quoted(work, "$", "$")); - version_length = strlen(work) + 1; - - if (!(new = ast_calloc(1, sizeof(*new) + version_length))) - return; - - new->file = file; - 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); - if (find) - free(find); -} - -struct thread_list_t { - AST_LIST_ENTRY(thread_list_t) list; - char *name; - pthread_t id; -}; - -static AST_LIST_HEAD_STATIC(thread_list, thread_list_t); - -static char show_threads_help[] = -"Usage: show threads\n" -" List threads currently active in the system.\n"; - -void ast_register_thread(char *name) -{ - struct thread_list_t *new = ast_calloc(1, sizeof(*new)); - - if (!new) - return; - new->id = pthread_self(); - new->name = name; /* this was a copy already */ - AST_LIST_LOCK(&thread_list); - AST_LIST_INSERT_HEAD(&thread_list, new, list); - AST_LIST_UNLOCK(&thread_list); -} - -void ast_unregister_thread(void *id) -{ - struct thread_list_t *x; - - AST_LIST_LOCK(&thread_list); - AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) { - if ((void *)x->id == id) { - AST_LIST_REMOVE_CURRENT(&thread_list, list); - break; - } - } - AST_LIST_TRAVERSE_SAFE_END; - AST_LIST_UNLOCK(&thread_list); - if (x) { - free(x->name); - free(x); - } -} - -static int handle_show_threads(int fd, int argc, char *argv[]) -{ - int count = 0; - struct thread_list_t *cur; - - AST_LIST_LOCK(&thread_list); - AST_LIST_TRAVERSE(&thread_list, cur, list) { - ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name); - count++; - } - AST_LIST_UNLOCK(&thread_list); - ast_cli(fd, "%d threads listed.\n", count); - return 0; -} - -struct profile_entry { - const char *name; - uint64_t scale; /* if non-zero, values are scaled by this */ - int64_t mark; - int64_t value; - int64_t events; -}; - -struct profile_data { - int entries; - int max_size; - struct profile_entry e[0]; -}; - -static struct profile_data *prof_data; - -/*! \brief allocates a counter with a given name and scale. - * \return Returns the identifier of the counter. - */ -int ast_add_profile(const char *name, uint64_t scale) -{ - int l = sizeof(struct profile_data); - int n = 10; /* default entries */ - - if (prof_data == NULL) { - prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry)); - if (prof_data == NULL) - return -1; - prof_data->entries = 0; - prof_data->max_size = n; - } - if (prof_data->entries >= prof_data->max_size) { - void *p; - n = prof_data->max_size + 20; - p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry)); - if (p == NULL) - return -1; - prof_data = p; - prof_data->max_size = n; - } - n = prof_data->entries++; - prof_data->e[n].name = ast_strdup(name); - prof_data->e[n].value = 0; - prof_data->e[n].events = 0; - prof_data->e[n].mark = 0; - prof_data->e[n].scale = scale; - return n; -} - -int64_t ast_profile(int i, int64_t delta) -{ - if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */ - return 0; - if (prof_data->e[i].scale > 1) - delta /= prof_data->e[i].scale; - prof_data->e[i].value += delta; - prof_data->e[i].events++; - return prof_data->e[i].value; -} - -#if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux)) -#if defined(__FreeBSD__) -#include -#elif defined(linux) -static __inline u_int64_t -rdtsc(void) -{ - uint64_t rv; - - __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv)); - return (rv); -} -#endif -#else /* supply a dummy function on other platforms */ -static __inline u_int64_t -rdtsc(void) -{ - return 0; -} -#endif - -int64_t ast_mark(int i, int startstop) -{ - if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */ - return 0; - if (startstop == 1) - prof_data->e[i].mark = rdtsc(); - else { - prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark); - if (prof_data->e[i].scale > 1) - prof_data->e[i].mark /= prof_data->e[i].scale; - prof_data->e[i].value += prof_data->e[i].mark; - prof_data->e[i].events++; - } - return prof_data->e[i].mark; -} - -static int handle_show_profile(int fd, int argc, char *argv[]) -{ - int i, min, max; - char *search = NULL; - - if (prof_data == NULL) - return 0; - - min = 0; - max = prof_data->entries; - if (argc >= 3) { /* specific entries */ - if (isdigit(argv[2][0])) { - min = atoi(argv[2]); - if (argc == 4 && strcmp(argv[3], "-")) - max = atoi(argv[3]); - } else - search = argv[2]; - } - if (max > prof_data->entries) - max = prof_data->entries; - if (!strcmp(argv[0], "clear")) { - for (i= min; i < max; i++) { - if (!search || strstr(prof_data->e[i].name, search)) { - prof_data->e[i].value = 0; - prof_data->e[i].events = 0; - } - } - return 0; - } - ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n", - prof_data->entries, prof_data->max_size); - for (i = min; i < max; i++) { - struct profile_entry *e = &prof_data->e[i]; - if (!search || strstr(prof_data->e[i].name, search)) - ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n", - i, - (long)e->scale, - (long)e->events, (long long)e->value, - (long long)(e->events ? e->value / e->events : e->value), - e->name); - } - return 0; -} - -static char show_version_files_help[] = -"Usage: show version files [like ]\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"; - -/*! \brief CLI command to list module versions */ -static int handle_show_version_files(int fd, int argc, char *argv[]) -{ -#define FORMAT "%-25.25s %-40.40s\n" - struct file_version *iterator; - regex_t regexbuf; - int havepattern = 0; - int havename = 0; - int count_files = 0; - - 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; - case 3: - break; - default: - return RESULT_SHOWUSAGE; - } - - 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; - - if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0)) - continue; - - ast_cli(fd, FORMAT, iterator->file, iterator->version); - count_files++; - if (havename) - break; - } - AST_LIST_UNLOCK(&file_versions); - if (!havename) { - ast_cli(fd, "%d files listed.\n", count_files); - } - - if (havepattern) - regfree(®exbuf); - - return RESULT_SUCCESS; -#undef FORMAT -} - -static char *complete_show_version_files(const char *line, const 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) && ++which > state) { - ret = ast_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); - AST_LIST_LOCK(&atexits); - if ((ae = ast_calloc(1, sizeof(*ae)))) { - AST_LIST_INSERT_HEAD(&atexits, ae, list); - ae->func = func; - res = 0; - } - AST_LIST_UNLOCK(&atexits); - return res; -} - -void ast_unregister_atexit(void (*func)(void)) -{ - struct ast_atexit *ae; - AST_LIST_LOCK(&atexits); - AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) { - if (ae->func == func) { - AST_LIST_REMOVE_CURRENT(&atexits, list); - break; - } - } - AST_LIST_TRAVERSE_SAFE_END - AST_LIST_UNLOCK(&atexits); -} - -static int fdprint(int fd, const char *s) -{ - return write(fd, s, strlen(s) + 1); -} - -/*! \brief NULL handler so we can collect the child exit status */ -static void null_sig_handler(int signal) -{ - -} - -AST_MUTEX_DEFINE_STATIC(safe_system_lock); -/*! \brief Keep track of how many threads are currently trying to wait*() on - * a child process */ -static unsigned int safe_system_level = 0; -static void *safe_system_prev_handler; - -void ast_replace_sigchld(void) -{ - unsigned int level; - - ast_mutex_lock(&safe_system_lock); - level = safe_system_level++; - - /* only replace the handler if it has not already been done */ - if (level == 0) - safe_system_prev_handler = signal(SIGCHLD, null_sig_handler); - - ast_mutex_unlock(&safe_system_lock); -} - -void ast_unreplace_sigchld(void) -{ - unsigned int level; - - ast_mutex_lock(&safe_system_lock); - level = --safe_system_level; - - /* only restore the handler if we are the last one */ - if (level == 0) - signal(SIGCHLD, safe_system_prev_handler); - - ast_mutex_unlock(&safe_system_lock); -} - -int ast_safe_system(const char *s) -{ - pid_t pid; - int x; - int res; - struct rusage rusage; - int status; - - ast_replace_sigchld(); - - pid = fork(); - - if (pid == 0) { - if (ast_opt_high_priority) - ast_set_priority(0); - /* Close file descriptors and launch system command */ - for (x = STDERR_FILENO + 1; x < 4096; x++) - close(x); - execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL); - exit(1); - } 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) - break; - } - } else { - ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); - res = -1; - } - - ast_unreplace_sigchld(); - - return res; -} - -/*! - * \brief mute or unmute a console from logging - */ -void ast_console_toggle_mute(int fd) { - int x; - for (x = 0;x < AST_MAX_CONNECTS; x++) { - if (fd == consoles[x].fd) { - if (consoles[x].mute) { - consoles[x].mute = 0; - ast_cli(fd, "Console is not muted anymore.\n"); - } else { - consoles[x].mute = 1; - ast_cli(fd, "Console is muted.\n"); - } - return; - } - } - ast_cli(fd, "Couldn't find remote console.\n"); -} - -/*! - * \brief log the string to all attached console clients - */ -static void ast_network_puts_mutable(const char *string) -{ - int x; - for (x = 0;x < AST_MAX_CONNECTS; x++) { - if (consoles[x].mute) - continue; - if (consoles[x].fd > -1) - fdprint(consoles[x].p[1], string); - } -} - -/*! - * \brief log the string to the console, and all attached - * console clients - */ -void ast_console_puts_mutable(const char *string) -{ - fputs(string, stdout); - fflush(stdout); - ast_network_puts_mutable(string); -} - -/*! - * \brief 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) -{ - ast_network_puts_mutable(s); -} - -static pthread_t lthread; - -static void *netconsole(void *vconsole) -{ - struct console *con = vconsole; - char hostname[MAXHOSTNAMELEN] = ""; - char tmp[512]; - int res; - struct pollfd fds[2]; - - if (gethostname(hostname, sizeof(hostname)-1)) - ast_copy_string(hostname, "", sizeof(hostname)); - snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION); - fdprint(con->fd, tmp); - for(;;) { - 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 (res < 0) { - if (errno != EINTR) - ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno)); - continue; - } - if (fds[0].revents) { - res = read(con->fd, tmp, sizeof(tmp)); - if (res < 1) { - break; - } - 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; - int s; - socklen_t len; - int x; - int flags; - struct pollfd fds[1]; - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - for (;;) { - if (ast_socket < 0) - return NULL; - fds[0].fd = ast_socket; - fds[0].events = POLLIN; - s = poll(fds, 1, -1); - pthread_testcancel(); - if (s < 0) { - if (errno != EINTR) - ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno)); - continue; - } - len = sizeof(sunaddr); - s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len); - if (s < 0) { - if (errno != EINTR) - 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); - consoles[x].fd = s; - consoles[x].mute = ast_opt_mute; - 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)); - close(consoles[x].p[0]); - close(consoles[x].p[1]); - 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; - int res; - int x; - uid_t uid = -1; - gid_t gid = -1; - - for (x = 0; x < AST_MAX_CONNECTS; x++) - consoles[x].fd = -1; - 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)); - if (res) { - 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)) { - struct passwd *pw; - 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)) { - struct group *grp; - 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)) { - int p1; - mode_t p; - sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1); - p = p1; - 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; -} - -/*! \brief Urgent handler - - Called by soft_hangup to interrupt the poll, read, or other - system call. We don't actually need to do anything though. - Remember: Cannot EVER ast_log from within a signal handler - */ -static void urg_handler(int num) -{ - signal(num, urg_handler); - return; -} - -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 */ - ast_module_reload(NULL); - 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"); - signal(sig, child_handler); -} - -/*! \brief Set an X-term or screen title */ -static void set_title(char *text) -{ - if (getenv("TERM") && strstr(getenv("TERM"), "xterm")) - fprintf(stdout, "\033]2;%s\007", text); -} - -static void set_icon(char *text) -{ - if (getenv("TERM") && strstr(getenv("TERM"), "xterm")) - fprintf(stdout, "\033]1;%s\007", text); -} - -/*! \brief We set ourselves to a high priority, that we might pre-empt everything - else. If your PBX has heavy activity on it, this is a good thing. */ -int ast_set_priority(int pri) -{ - struct sched_param sched; - memset(&sched, 0, sizeof(sched)); -#ifdef __linux__ - if (pri) { - 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 - return 0; -} - -static void ast_run_atexits(void) -{ - struct ast_atexit *ae; - AST_LIST_LOCK(&atexits); - AST_LIST_TRAVERSE(&atexits, ae, list) { - if (ae->func) - ae->func(); - } - AST_LIST_UNLOCK(&atexits); -} - -static void quit_handler(int num, int nice, int safeshutdown, int restart) -{ - char filename[80] = ""; - time_t s,e; - int x; - /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */ - ast_cdr_engine_term(); - if (safeshutdown) { - shuttingdown = 1; - if (!nice) { - /* Begin shutdown routine, hanging up active channels */ - ast_begin_shutdown(1); - if (option_verbose && ast_opt_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 && ast_opt_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 && ast_opt_console) - ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown"); - return; - } - } - if (ast_opt_console || ast_opt_remote) { - if (getenv("HOME")) - snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); - if (!ast_strlen_zero(filename)) - 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(); - /* Called on exit */ - if (option_verbose && ast_opt_console) - 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_socket > -1) { - pthread_cancel(lthread); - close(ast_socket); - ast_socket = -1; - unlink(ast_config_AST_SOCKET); - } - if (ast_consock > -1) - close(ast_consock); - if (!ast_opt_remote) - unlink(ast_config_AST_PID); - printf(term_quit()); - if (restart) { - if (option_verbose || ast_opt_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 || ast_opt_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); - term_color(outbuf, cmp, COLOR_GRAY, 0, maxout); - return c; - } - return NULL; -} - -static void console_verboser(const char *s) -{ - char tmp[80]; - const char *c = NULL; - - if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) || - (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) || - (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) || - (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) { - fputs(tmp, stdout); - fputs(c, stdout); - } else - fputs(s, stdout); - - fflush(stdout); - - /* Wake up a poll()ing console */ - if (ast_opt_console && consolethread != AST_PTHREADT_NULL) - pthread_kill(consolethread, SIGURG); -} - -static int ast_all_zeros(char *s) -{ - while (*s) { - if (*s > 32) - return 0; - s++; - } - return 1; -} - -static void consolehandler(char *s) -{ - printf(term_end()); - fflush(stdout); - - /* Called when readline data is available */ - if (!ast_all_zeros(s)) - ast_el_add_history(s); - /* The real handler for bang */ - if (s[0] == '!') { - if (s[1]) - ast_safe_system(s+1); - else - ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh"); - } else - ast_cli_command(STDOUT_FILENO, s); -} - -static int remoteconsolehandler(char *s) -{ - int ret = 0; - - /* Called when readline data is available */ - if (!ast_all_zeros(s)) - ast_el_add_history(s); - /* The real handler for bang */ - if (s[0] == '!') { - if (s[1]) - ast_safe_system(s+1); - else - ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh"); - ret = 1; - } - if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) && - (s[4] == '\0' || isspace(s[4]))) { - quit_handler(0, 0, 0, 0); - ret = 1; - } - - return ret; -} - -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[] = -"Usage: stop now\n" -" Shuts down a running Asterisk immediately, hanging up all active calls .\n"; - -static char shutdown_gracefully_help[] = -"Usage: stop gracefully\n" -" 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: !\n" -" Executes a given shell command\n"; - -static char show_warranty_help[] = -"Usage: show warranty\n" -" Shows the warranty (if any) for this copy of Asterisk.\n"; - -static char show_license_help[] = -"Usage: show license\n" -" Shows the license(s) for this copy of Asterisk.\n"; - -static char version_help[] = -"Usage: show version\n" -" Shows Asterisk version information.\n"; - -static int handle_version(int fd, int argc, char *argv[]) -{ - if (argc != 2) - return RESULT_SHOWUSAGE; - ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n", - ASTERISK_VERSION, ast_build_user, ast_build_hostname, - ast_build_machine, ast_build_os, ast_build_date); - return RESULT_SUCCESS; -} - -#if 0 -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; -} -#endif - -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; - ast_cli(fd, "Waiting for inactivity to perform halt\n"); - quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */); - return RESULT_SUCCESS; -} - -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; - ast_cli(fd, "Waiting for inactivity to perform restart\n"); - 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; - return RESULT_SUCCESS; -} - -static int handle_bang(int fd, int argc, char *argv[]) -{ - return RESULT_SUCCESS; -} -static const char *warranty_lines[] = { - "\n", - " NO WARRANTY\n", - "\n", - "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n", - "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n", - "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n", - "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n", - "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n", - "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n", - "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n", - "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n", - "REPAIR OR CORRECTION.\n", - "\n", - "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n", - "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n", - "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n", - "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n", - "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n", - "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n", - "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n", - "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n", - "POSSIBILITY OF SUCH DAMAGES.\n", -}; - -static int show_warranty(int fd, int argc, char *argv[]) -{ - int x; - - for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++) - ast_cli(fd, (char *) warranty_lines[x]); - - return RESULT_SUCCESS; -} - -static const char *license_lines[] = { - "\n", - "This program is free software; you can redistribute it and/or modify\n", - "it under the terms of the GNU General Public License version 2 as\n", - "published by the Free Software Foundation.\n", - "\n", - "This program also contains components licensed under other licenses.\n", - "They include:\n", - "\n", - "This program is distributed in the hope that it will be useful,\n", - "but WITHOUT ANY WARRANTY; without even the implied warranty of\n", - "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n", - "GNU General Public License for more details.\n", - "\n", - "You should have received a copy of the GNU General Public License\n", - "along with this program; if not, write to the Free Software\n", - "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n", -}; - -static int show_license(int fd, int argc, char *argv[]) -{ - int x; - - for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++) - ast_cli(fd, (char *) license_lines[x]); - - return RESULT_SUCCESS; -} - -#define ASTERISK_PROMPT "*CLI> " - -#define ASTERISK_PROMPT2 "%s*CLI> " - -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 }, - { { "show", "warranty", NULL }, show_warranty, - "Show the warranty (if any) for this copy of Asterisk", show_warranty_help }, - { { "show", "license", NULL }, show_license, - "Show the license(s) for this copy of Asterisk", show_license_help }, - { { "show", "version", NULL }, handle_version, - "Display version info", version_help }, - { { "!", NULL }, handle_bang, - "Execute a shell command", bang_help }, -#if !defined(LOW_MEMORY) - { { "show", "version", "files", NULL }, handle_show_version_files, - "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files }, - { { "show", "threads", NULL }, handle_show_threads, - "Show running threads", show_threads_help, NULL }, - { { "show", "profile", NULL }, handle_show_profile, - "Show profiling info"}, - { { "clear", "profile", NULL }, handle_show_profile, - "Clear profiling info"}, -#endif /* ! LOW_MEMORY */ -}; - -static int ast_el_read_char(EditLine *el, char *cp) -{ - int num_read = 0; - int lastpos = 0; - struct pollfd fds[2]; - int res; - int max; - char buf[512]; - - for (;;) { - max = 1; - fds[0].fd = ast_consock; - fds[0].events = POLLIN; - if (!ast_opt_exec) { - 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)); - break; - } - - if (!ast_opt_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 (!ast_opt_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()); - WELCOME_MESSAGE; - break; - } else { - usleep(1000000 / reconnects_per_second); - } - } - if (tries >= 30 * reconnects_per_second) { - fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n"); - quit_handler(0, 0, 0, 0); - } - } - } - - buf[res] = '\0'; - - if (!ast_opt_exec && !lastpos) - write(STDOUT_FILENO, "\r", 1); - write(STDOUT_FILENO, buf, res); - if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) { - *cp = CC_REFRESH; - return(1); - } else { - lastpos = 1; - } - } - } - - *cp = '\0'; - return (0); -} - -static char *cli_prompt(EditLine *el) -{ - static char prompt[200]; - char *pfmt; - int color_used = 0; - char term_code[20]; - - if ((pfmt = getenv("ASTERISK_PROMPT"))) { - char *t = pfmt, *p = prompt; - memset(prompt, 0, sizeof(prompt)); - while (*t != '\0' && *p < sizeof(prompt)) { - if (*t == '%') { - char hostname[MAXHOSTNAMELEN]=""; - int i; - time_t ts; - struct tm tm; -#ifdef linux - FILE *LOADAVG; -#endif - int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK; - - t++; - switch (*t) { - case 'C': /* color */ - t++; - if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) { - strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1); - t += i - 1; - } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) { - strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1); - t += i - 1; - } - - /* If the color has been reset correctly, then there's no need to reset it later */ - if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) { - color_used = 0; - } else { - color_used = 1; - } - break; - case 'd': /* date */ - memset(&tm, 0, sizeof(tm)); - time(&ts); - if (localtime_r(&ts, &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) - 1); - } else { - strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1); - } - break; - case 'H': /* short hostname */ - if (!gethostname(hostname, sizeof(hostname) - 1)) { - for (i = 0; i < sizeof(hostname); i++) { - if (hostname[i] == '.') { - hostname[i] = '\0'; - break; - } - } - strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1); - } else { - strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1); - } - 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 's': /* Asterisk system name (from asterisk.conf) */ - strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1); - break; - case 't': /* time */ - memset(&tm, 0, sizeof(tm)); - time(&ts); - if (localtime_r(&ts, &tm)) { - strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm); - } - break; - case '#': /* process console or remote? */ - if (!ast_opt_remote) { - strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1); - } else { - strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1); - } - break; - case '%': /* literal % */ - strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1); - break; - case '\0': /* % is last character - prevent bug */ - t--; - break; - } - while (*p != '\0') { - p++; - } - t++; - } else { - *p = *t; - p++; - t++; - } - } - if (color_used) { - /* Force colors back to normal at end */ - term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code)); - if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) { - strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code)); - } else { - strncat(p, term_code, sizeof(term_code)); - } - } - } else if (remotehostname) - snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname); - else - snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT); - - return(prompt); -} - -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) { - - if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) - break; - if (matches + 1 >= match_list_len) { - match_list_len <<= 1; - if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) { - /* TODO: Handle memory allocation failure */ - } - } - - match_list[matches++] = strdup(retstr); - } - - if (!match_list) - return (char **) NULL; - - if (matches >= match_list_len) { - if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) { - /* TODO: Handle memory allocation failure */ - } - } - - 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), 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--; - free(matches[idx]); - matches[idx] = NULL; - continue; - } - - numoutput++; - numoutputline++; - fprintf(stdout, "%-*s ", max, matches[idx]); - free(matches[idx]); - matches[idx] = NULL; - } - if (numoutputline > 0) - fprintf(stdout, "\n"); - } - - return numoutput; -} - - -static char *cli_complete(EditLine *el, int ch) -{ - int len = 0; - char *ptr; - int nummatches = 0; - char **matches; - int retval = CC_ERROR; - char buf[2048]; - int res; - - LineInfo *lf = (LineInfo *)el_line(el); - - *(char *)lf->cursor = '\0'; - ptr = (char *)lf->cursor; - if (ptr) { - while (ptr > lf->buffer) { - if (isspace(*ptr)) { - ptr++; - break; - } - ptr--; - } - } - - len = lf->cursor - ptr; - - if (ast_opt_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) { - char *mbuf; - int mlen = 0, maxmbuf = 2048; - /* Start with a 2048 byte buffer */ - if (!(mbuf = ast_malloc(maxmbuf))) - return (char *)(CC_ERROR); - snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); - fdprint(ast_consock, buf); - res = 0; - mbuf[0] = '\0'; - while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) { - if (mlen + 1024 > maxmbuf) { - /* Every step increment buffer 1024 bytes */ - maxmbuf += 1024; - if (!(mbuf = ast_realloc(mbuf, maxmbuf))) - return (char *)(CC_ERROR); - } - /* Only read 1024 bytes at a time */ - res = read(ast_consock, mbuf + mlen, 1024); - if (res > 0) - mlen += res; - } - mbuf[mlen] = '\0'; - - matches = ast_el_strtoarr(mbuf); - free(mbuf); - } else - matches = (char **) NULL; - } else { - char **p, *oldbuf=NULL; - nummatches = 0; - matches = ast_cli_completion_matches((char *)lf->buffer,ptr); - for (p = matches; p && *p; p++) { - if (!oldbuf || strcmp(*p,oldbuf)) - nummatches++; - oldbuf = *p; - } - } - - 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 */ - el_insertstr(el, " "); - 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 { - el_insertstr(el," "); - retval = CC_REFRESH; - } - } - free(matches); - } - - return (char *)(long)retval; -} - -static int ast_el_initialize(void) -{ - HistEvent ev; - char *editor = getenv("AST_EDITOR"); - - 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, editor ? 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 to command completion */ - el_set(el, EL_BIND, "^I", "ed-complete", NULL); - /* Bind ? to command completion */ - el_set(el, EL_BIND, "?", "ed-complete", NULL); - /* Bind ^D to redisplay */ - el_set(el, EL_BIND, "^D", "ed-redisplay", NULL); - - return 0; -} - -static int ast_el_add_history(char *buf) -{ - HistEvent ev; - - if (el_hist == NULL || el == NULL) - ast_el_initialize(); - if (strlen(buf) > 256) - return 0; - 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 (ast_all_zeros(buf)) - continue; - if ((ret = ast_el_add_history(buf)) == -1) - break; - } - fclose(f); - - return ret; -} - -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]; - char *stringp = NULL; - - char *ebuf; - int num = 0; - - read(ast_consock, buf, sizeof(buf)); - if (data) - write(ast_consock, data, strlen(data) + 1); - stringp = buf; - hostname = strsep(&stringp, "/"); - cpid = strsep(&stringp, "/"); - version = strsep(&stringp, "\n"); - if (!version) - version = ""; - stringp = hostname; - strsep(&stringp, "."); - if (cpid) - pid = atoi(cpid); - else - pid = -1; - snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose); - fdprint(ast_consock, tmp); - snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug); - fdprint(ast_consock, tmp); - if (ast_opt_mute) { - snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)"); - fdprint(ast_consock, tmp); - } - ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid); - remotehostname = hostname; - if (getenv("HOME")) - snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); - if (el_hist == NULL || el == NULL) - ast_el_initialize(); - - el_set(el, EL_GETCFN, ast_el_read_char); - - if (!ast_strlen_zero(filename)) - ast_el_read_history(filename); - - if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */ - char tempchar; - struct pollfd fds; - fds.fd = ast_consock; - fds.events = POLLIN; - fds.revents = 0; - while (poll(&fds, 1, 100) > 0) - ast_el_read_char(el, &tempchar); - return; - } - for (;;) { - ebuf = (char *)el_gets(el, &num); - - if (!ast_strlen_zero(ebuf)) { - if (ebuf[strlen(ebuf)-1] == '\n') - ebuf[strlen(ebuf)-1] = '\0'; - if (!remoteconsolehandler(ebuf)) { - res = write(ast_consock, ebuf, strlen(ebuf) + 1); - if (res < 1) { - ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno)); - break; - } - } - } - } - printf("\nDisconnected from Asterisk server\n"); -} - -static int show_version(void) -{ - printf("Asterisk " ASTERISK_VERSION "\n"); - return 0; -} - -static int show_cli_help(void) { - printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n"); - printf("Usage: asterisk [OPTIONS]\n"); - printf("Valid Options:\n"); - printf(" -V Display version number and exit\n"); - printf(" -C Use an alternate configuration file\n"); - printf(" -G Run as a group other than the caller\n"); - printf(" -U Run as a user other than the caller\n"); - printf(" -c Provide console CLI\n"); - printf(" -d Enable extra debugging\n"); - printf(" -f Do not fork\n"); - printf(" -g Dump core in case of a crash\n"); - printf(" -h This help screen\n"); - printf(" -i Initialize crypto keys at startup\n"); - printf(" -I Enable internal timing if Zaptel timer is available\n"); - printf(" -L Limit the maximum load average before rejecting new calls\n"); - printf(" -M Limit the maximum number of calls to the specified value\n"); - printf(" -m Mute the console from debugging and verbose output\n"); - printf(" -n Disable console colorization\n"); - printf(" -p Run as pseudo-realtime thread\n"); - printf(" -q Quiet mode (suppress output)\n"); - printf(" -r Connect to Asterisk on this machine\n"); - printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n"); - printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n"); - printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n"); - printf(" -v Increase verbosity (multiple v's = more verbose)\n"); - printf(" -x Execute command (only valid with -r)\n"); - printf("\n"); - return 0; -} - -static void ast_readconfig(void) -{ - struct ast_config *cfg; - struct ast_variable *v; - char *config = AST_CONFIG_FILE; - - if (ast_opt_override_config) { - cfg = ast_config_load(ast_config_AST_CONFIG_FILE); - if (!cfg) - ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE); - } else { - cfg = ast_config_load(config); - } - - /* init with buildtime config */ - ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR)); - ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR)); - ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR)); - snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR); - ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR)); - ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR)); - ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR)); - ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR)); - ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB)); - ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR)); - ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID)); - ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET)); - ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR)); - - /* no asterisk.conf? no problem, use buildtime config! */ - if (!cfg) { - return; - } - - for (v = ast_variable_browse(cfg, "files"); v; v = v->next) { - if (!strcasecmp(v->name, "astctlpermissions")) { - ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS)); - } else if (!strcasecmp(v->name, "astctlowner")) { - ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER)); - } else if (!strcasecmp(v->name, "astctlgroup")) { - ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP)); - } else if (!strcasecmp(v->name, "astctl")) { - ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL)); - } - } - - for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) { - if (!strcasecmp(v->name, "astetcdir")) { - ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR)); - } else if (!strcasecmp(v->name, "astspooldir")) { - ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR)); - snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value); - } else if (!strcasecmp(v->name, "astvarlibdir")) { - ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR)); - snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value); - } else if (!strcasecmp(v->name, "astdatadir")) { - ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR)); - snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value); - } else if (!strcasecmp(v->name, "astlogdir")) { - ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR)); - } else if (!strcasecmp(v->name, "astagidir")) { - ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR)); - } else if (!strcasecmp(v->name, "astrundir")) { - snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid"); - snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL); - ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR)); - } else if (!strcasecmp(v->name, "astmoddir")) { - ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR)); - } - } - - for (v = ast_variable_browse(cfg, "options"); v; v = v->next) { - /* verbose level (-v at startup) */ - if (!strcasecmp(v->name, "verbose")) { - option_verbose = atoi(v->value); - /* whether or not to force timestamping in CLI verbose output. (-T at startup) */ - } else if (!strcasecmp(v->name, "timestamp")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP); - /* whether or not to support #exec in config files */ - } else if (!strcasecmp(v->name, "execincludes")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES); - /* debug level (-d at startup) */ - } else if (!strcasecmp(v->name, "debug")) { - option_debug = 0; - if (sscanf(v->value, "%d", &option_debug) != 1) { - option_debug = ast_true(v->value); - } - /* Disable forking (-f at startup) */ - } else if (!strcasecmp(v->name, "nofork")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK); - /* Always fork, even if verbose or debug are enabled (-F at startup) */ - } else if (!strcasecmp(v->name, "alwaysfork")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK); - /* Run quietly (-q at startup ) */ - } else if (!strcasecmp(v->name, "quiet")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET); - /* Run as console (-c at startup, implies nofork) */ - } else if (!strcasecmp(v->name, "console")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE); - /* Run with high priority if the O/S permits (-p at startup) */ - } else if (!strcasecmp(v->name, "highpriority")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY); - /* Initialize RSA auth keys (IAX2) (-i at startup) */ - } else if (!strcasecmp(v->name, "initcrypto")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS); - /* Disable ANSI colors for console (-c at startup) */ - } else if (!strcasecmp(v->name, "nocolor")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR); - /* Disable some usage warnings for picky people :p */ - } else if (!strcasecmp(v->name, "dontwarn")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN); - /* Dump core in case of crash (-g) */ - } else if (!strcasecmp(v->name, "dumpcore")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE); - /* Cache recorded sound files to another directory during recording */ - } else if (!strcasecmp(v->name, "cache_record_files")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES); - /* Specify cache directory */ - } else if (!strcasecmp(v->name, "record_cache_dir")) { - ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN); - /* Build transcode paths via SLINEAR, instead of directly */ - } else if (!strcasecmp(v->name, "transcode_via_sln")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN); - /* Transmit SLINEAR silence while a channel is being recorded */ - } else if (!strcasecmp(v->name, "transmit_silence_during_record")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE); - /* Enable internal timing */ - } else if (!strcasecmp(v->name, "internal_timing")) { - ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING); - } else if (!strcasecmp(v->name, "maxcalls")) { - if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) { - option_maxcalls = 0; - } - } else if (!strcasecmp(v->name, "maxload")) { - double test[1]; - - if (getloadavg(test, 1) == -1) { - ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n"); - option_maxload = 0.0; - } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) { - option_maxload = 0.0; - } - /* What user to run as */ - } else if (!strcasecmp(v->name, "runuser")) { - ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER)); - /* What group to run as */ - } else if (!strcasecmp(v->name, "rungroup")) { - ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP)); - } else if (!strcasecmp(v->name, "systemname")) { - ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME)); - } else if (!strcasecmp(v->name, "languageprefix")) { - ast_language_is_prefix = ast_true(v->value); - } - } - ast_config_destroy(cfg); -} - -int main(int argc, char *argv[]) -{ - int c; - char filename[80] = ""; - char hostname[MAXHOSTNAMELEN] = ""; - char tmp[80]; - char * xarg = NULL; - int x; - FILE *f; - sigset_t sigs; - int num; - int is_child_of_nonroot = 0; - char *buf; - char *runuser = NULL, *rungroup = NULL; - - /* Remember original args for restart */ - if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) { - fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1); - argc = sizeof(_argv) / sizeof(_argv[0]) - 1; - } - for (x=0; x", sizeof(hostname)); - ast_mainpid = getpid(); - ast_ulaw_init(); - ast_alaw_init(); - callerid_init(); - ast_builtins_init(); - ast_utils_init(); - tdd_init(); - /* When Asterisk restarts after it has dropped the root privileges, - * it can't issue setuid(), setgid(), setgroups() or set_priority() - */ - if (getenv("ASTERISK_ALREADY_NONROOT")) - is_child_of_nonroot=1; - if (getenv("HOME")) - snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME")); - /* Check for options */ - while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) { - switch (c) { - case 'F': - ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK); - break; - case 'd': - option_debug++; - ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK); - break; - case 'c': - ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE); - break; - case 'f': - ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK); - break; - case 'n': - ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR); - break; - case 'r': - ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE); - break; - case 'R': - ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT); - break; - case 'p': - ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY); - break; - case 'v': - option_verbose++; - ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK); - break; - case 'm': - ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE); - break; - case 'M': - if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) - option_maxcalls = 0; - break; - case 'L': - if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) - option_maxload = 0.0; - break; - case 'q': - ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET); - break; - case 't': - ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES); - break; - case 'T': - ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP); - break; - case 'x': - ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC); - xarg = optarg; - break; - case 'C': - ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE)); - ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG); - break; - case 'I': - ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING); - break; - case 'i': - ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS); - break; - case 'g': - ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE); - break; - case 'h': - show_cli_help(); - exit(0); - case 'V': - show_version(); - exit(0); - case 'U': - runuser = optarg; - break; - case 'G': - rungroup = optarg; - break; - case '?': - exit(1); - } - } - - if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) { - ast_register_verbose(console_verboser); - WELCOME_MESSAGE; - } - - if (ast_opt_console && !option_verbose) - ast_verbose("[ Booting...\n"); - - if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) { - ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n"); - ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK); - } - - /* For remote connections, change the name of the remote connection. - * We do this for the benefit of init scripts (which need to know if/when - * the main asterisk process has died yet). */ - if (ast_opt_remote) { - strcpy(argv[0], "rasterisk"); - for (x = 1; x < argc; x++) { - argv[x] = argv[0] + 10; - } - } - - if (ast_opt_console && !option_verbose) - ast_verbose("[ Reading Master Configuration ]\n"); - ast_readconfig(); - - if (ast_opt_dump_core) { - 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)); - } - } - - if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP)) - rungroup = ast_config_AST_RUN_GROUP; - if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER)) - runuser = ast_config_AST_RUN_USER; - -#ifndef __CYGWIN__ - - if (!is_child_of_nonroot) - ast_set_priority(ast_opt_high_priority); - - if (!is_child_of_nonroot && rungroup) { - struct group *gr; - gr = getgrnam(rungroup); - if (!gr) { - ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup); - exit(1); - } - if (setgid(gr->gr_gid)) { - ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup); - exit(1); - } - if (setgroups(0, NULL)) { - ast_log(LOG_WARNING, "Unable to drop unneeded groups\n"); - exit(1); - } - if (option_verbose) - ast_verbose("Running as group '%s'\n", rungroup); - } - - if (!is_child_of_nonroot && runuser) { - struct passwd *pw; - pw = getpwnam(runuser); - if (!pw) { - ast_log(LOG_WARNING, "No such user '%s'!\n", runuser); - exit(1); - } - if (!rungroup) { - if (setgid(pw->pw_gid)) { - ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid); - exit(1); - } - if (initgroups(pw->pw_name, pw->pw_gid)) { - ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser); - exit(1); - } - } - if (setuid(pw->pw_uid)) { - ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser); - exit(1); - } - setenv("ASTERISK_ALREADY_NONROOT", "yes", 1); - if (option_verbose) - ast_verbose("Running as user '%s'\n", runuser); - } - -#endif /* __CYGWIN__ */ - -#ifdef linux - if (geteuid() && ast_opt_dump_core) { - if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) { - ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno)); - } - } -#endif - - term_init(); - printf(term_end()); - fflush(stdout); - - if (ast_opt_console && !option_verbose) - ast_verbose("[ Initializing Custom Configuration Options ]\n"); - /* custom config setup */ - register_config_cli(); - read_config_maps(); - - if (ast_opt_console) { - if (el_hist == NULL || el == NULL) - ast_el_initialize(); - - if (!ast_strlen_zero(filename)) - ast_el_read_history(filename); - } - - if (ast_tryconnect()) { - /* One is already running */ - if (ast_opt_remote) { - if (ast_opt_exec) { - ast_remotecontrol(xarg); - quit_handler(0, 0, 0, 0); - exit(0); - } - printf(term_quit()); - ast_remotecontrol(NULL); - quit_handler(0, 0, 0, 0); - exit(0); - } else { - ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET); - printf(term_quit()); - exit(1); - } - } else if (ast_opt_remote || ast_opt_exec) { - ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET); - printf(term_quit()); - exit(1); - } - /* Blindly write pid file since we couldn't connect */ - unlink(ast_config_AST_PID); - f = fopen(ast_config_AST_PID, "w"); - if (f) { - fprintf(f, "%ld\n", (long)getpid()); - fclose(f); - } else - ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno)); - - if (ast_opt_always_fork || !ast_opt_no_fork) { - daemon(0, 0); - ast_mainpid = getpid(); - /* Blindly re-write pid file since we are forking */ - unlink(ast_config_AST_PID); - f = fopen(ast_config_AST_PID, "w"); - if (f) { - fprintf(f, "%ld\n", (long)ast_mainpid); - fclose(f); - } else - ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno)); - } - - /* Test recursive mutex locking. */ - if (test_for_thread_safety()) - ast_verbose("Warning! Asterisk is not thread safe.\n"); - - 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); - signal(SIGURG, urg_handler); - signal(SIGINT, __quit_handler); - signal(SIGTERM, __quit_handler); - signal(SIGHUP, hup_handler); - signal(SIGCHLD, child_handler); - signal(SIGPIPE, SIG_IGN); - - /* ensure that the random number generators are seeded with a different value every time - Asterisk is started - */ - srand((unsigned int) getpid() + (unsigned int) time(NULL)); - initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool)); - - if (init_logger()) { - printf(term_quit()); - exit(1); - } - if (dnsmgr_init()) { - printf(term_quit()); - exit(1); - } - /* load 'preload' modules, required for access to Realtime-mapped configuration files */ - if (load_modules(1)) { - printf(term_quit()); - exit(1); - } - ast_http_init(); - ast_channels_init(); - if (init_manager()) { - printf(term_quit()); - exit(1); - } - if (ast_cdr_engine_init()) { - printf(term_quit()); - exit(1); - } - if (ast_device_state_engine_init()) { - printf(term_quit()); - exit(1); - } - ast_rtp_init(); - ast_udptl_init(); - if (ast_image_init()) { - printf(term_quit()); - exit(1); - } - if (ast_file_init()) { - printf(term_quit()); - exit(1); - } - if (load_pbx()) { - printf(term_quit()); - exit(1); - } - if (load_modules(0)) { - printf(term_quit()); - exit(1); - } - if (init_framer()) { - printf(term_quit()); - exit(1); - } - if (astdb_init()) { - printf(term_quit()); - exit(1); - } - if (ast_enum_init()) { - printf(term_quit()); - exit(1); - } - - dnsmgr_start_refresh(); - -#if 0 - /* This should no longer be necessary */ - /* sync cust config and reload some internals in case a custom config handler binded to them */ - read_ast_cust_config(); - reload_logger(0); - reload_manager(); - ast_enum_reload(); - ast_rtp_reload(); -#endif - - /* We might have the option of showing a console, but for now just - do nothing... */ - if (ast_opt_console && !option_verbose) - ast_verbose(" ]\n"); - if (option_verbose || ast_opt_console) - ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp))); - if (ast_opt_no_fork) - consolethread = pthread_self(); - ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED); - pthread_sigmask(SIG_UNBLOCK, &sigs, NULL); -#ifdef __AST_DEBUG_MALLOC - __ast_mm_init(); -#endif - time(&ast_startuptime); - ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0])); - if (ast_opt_console) { - /* Console stuff now... */ - /* Register our quit function */ - char title[256]; - set_icon("Asterisk"); - snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid); - set_title(title); - - for (;;) { - buf = (char *)el_gets(el, &num); - if (buf) { - if (buf[strlen(buf)-1] == '\n') - buf[strlen(buf)-1] = '\0'; - - consolehandler((char *)buf); - } else { - if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n", - strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) { - /* Whoa, stdout disappeared from under us... Make /dev/null's */ - int fd; - fd = open("/dev/null", O_RDWR); - if (fd > -1) { - dup2(fd, STDOUT_FILENO); - dup2(fd, STDIN_FILENO); - } else - ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n"); - break; - } - } - } - - } - /* Do nothing */ - for(;;) { /* apparently needed for the MACos */ - struct pollfd p = { -1 /* no descriptor */, 0, 0 }; - poll(&p, 0, -1); - } - return 0; -} -- cgit v1.2.3