2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
22 * \mainpage Asterisk -- An Open Source Telephony Toolkit
24 * \par Developer Documentation for Asterisk
25 * This is the main developer documentation for Asterisk. It is
26 * generated by running "make progdocs".
27 * \par Additional documentation
29 * \arg \ref ConfigFiles
31 * \section copyright Copyright and author
33 * Copyright (C) 1999 - 2005, Digium, Inc.
34 * Asterisk is a trade mark registered by Digium, Inc.
36 * \author Mark Spencer <markster@digium.com>
37 * Also see \ref AstCREDITS
39 * \section license License
40 * See http://www.asterisk.org for more information about
41 * the Asterisk project. Please do not directly contact
42 * any of the maintainers of this project for assistance;
43 * the project provides a web site, mailing lists and IRC
44 * channels for your use.
46 * This program is free software, distributed under the terms of
47 * the GNU General Public License Version 2. See the LICENSE file
48 * at the top of the source tree.
50 * \verbinclude LICENSE
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
67 #include <sys/socket.h>
73 #include <sys/resource.h>
79 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
85 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
87 #include "asterisk/logger.h"
88 #include "asterisk/options.h"
89 #include "asterisk/cli.h"
90 #include "asterisk/channel.h"
91 #include "asterisk/ulaw.h"
92 #include "asterisk/alaw.h"
93 #include "asterisk/callerid.h"
94 #include "asterisk/module.h"
95 #include "asterisk/image.h"
96 #include "asterisk/tdd.h"
97 #include "asterisk/term.h"
98 #include "asterisk/manager.h"
99 #include "asterisk/cdr.h"
100 #include "asterisk/pbx.h"
101 #include "asterisk/enum.h"
102 #include "asterisk/rtp.h"
103 #include "asterisk/app.h"
104 #include "asterisk/lock.h"
105 #include "asterisk/utils.h"
106 #include "asterisk/file.h"
107 #include "asterisk/io.h"
108 #include "asterisk/lock.h"
109 #include "editline/histedit.h"
110 #include "asterisk/config.h"
111 #include "asterisk/version.h"
112 #include "asterisk/linkedlists.h"
113 #include "asterisk/devicestate.h"
114 #include "asterisk/compat.h"
116 #include "asterisk/doxyref.h" /* Doxygen documentation */
118 #include "defaults.h"
121 #define AF_LOCAL AF_UNIX
122 #define PF_LOCAL PF_UNIX
125 #define AST_MAX_CONNECTS 128
128 /*! \brief Welcome message when starting a CLI interface */
129 #define WELCOME_MESSAGE \
130 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005 Digium, Inc. and others.\n"); \
131 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
132 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
133 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
134 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
135 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
136 ast_verbose("=========================================================================\n")
138 /*! \defgroup main_options
139 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
140 the operating system command line when starting Asterisk
141 Some of them can be changed in the CLI
145 struct ast_flags ast_options = { AST_OPT_FLAG_TRANSCODE_VIA_SLIN };
147 int option_verbose = 0; /*!< Verbosity level */
148 int option_debug = 0; /*!< Debug level */
150 double option_maxload = 0.0; /*!< Max load avg on system */
151 int option_maxcalls = 0; /*!< Max number of active calls */
155 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
156 char debug_filename[AST_FILENAME_MAX] = "";
158 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
159 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
162 int fd; /*!< File descriptor */
163 int p[2]; /*!< Pipe */
164 pthread_t t; /*!< Thread of handler */
167 static struct ast_atexit {
169 struct ast_atexit *next;
172 AST_MUTEX_DEFINE_STATIC(atexitslock);
174 time_t ast_startuptime;
175 time_t ast_lastreloadtime;
177 static History *el_hist = NULL;
178 static EditLine *el = NULL;
179 static char *remotehostname;
181 struct console consoles[AST_MAX_CONNECTS];
183 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
185 static int ast_el_add_history(char *);
186 static int ast_el_read_history(char *);
187 static int ast_el_write_history(char *);
189 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
190 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
191 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
192 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
193 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
194 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
195 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
196 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
197 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
198 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
199 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
200 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
201 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
202 char ast_config_AST_RUN_USER[AST_CONFIG_MAX_PATH];
203 char ast_config_AST_RUN_GROUP[AST_CONFIG_MAX_PATH];
204 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
205 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
206 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
207 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
209 static char *_argv[256];
210 static int shuttingdown = 0;
211 static int restartnow = 0;
212 static pthread_t consolethread = AST_PTHREADT_NULL;
214 #if !defined(LOW_MEMORY)
215 struct file_version {
216 AST_LIST_ENTRY(file_version) list;
221 static AST_LIST_HEAD_STATIC(file_versions, file_version);
223 void ast_register_file_version(const char *file, const char *version)
225 struct file_version *new;
227 size_t version_length;
229 work = ast_strdupa(version);
230 work = ast_strip(ast_strip_quoted(work, "$", "$"));
231 version_length = strlen(work) + 1;
233 new = calloc(1, sizeof(*new) + version_length);
238 new->version = (char *) new + sizeof(*new);
239 memcpy(new->version, work, version_length);
240 AST_LIST_LOCK(&file_versions);
241 AST_LIST_INSERT_HEAD(&file_versions, new, list);
242 AST_LIST_UNLOCK(&file_versions);
245 void ast_unregister_file_version(const char *file)
247 struct file_version *find;
249 AST_LIST_LOCK(&file_versions);
250 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
251 if (!strcasecmp(find->file, file)) {
252 AST_LIST_REMOVE_CURRENT(&file_versions, list);
256 AST_LIST_TRAVERSE_SAFE_END;
257 AST_LIST_UNLOCK(&file_versions);
262 static char show_version_files_help[] =
263 "Usage: show version files [like <pattern>]\n"
264 " Shows the revision numbers of the files used to build this copy of Asterisk.\n"
265 " Optional regular expression pattern is used to filter the file list.\n";
267 /*! CLI command to list module versions */
268 static int handle_show_version_files(int fd, int argc, char *argv[])
270 #define FORMAT "%-25.25s %-40.40s\n"
271 struct file_version *iterator;
279 if (!strcasecmp(argv[3], "like")) {
280 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
281 return RESULT_SHOWUSAGE;
284 return RESULT_SHOWUSAGE;
292 return RESULT_SHOWUSAGE;
295 ast_cli(fd, FORMAT, "File", "Revision");
296 ast_cli(fd, FORMAT, "----", "--------");
297 AST_LIST_LOCK(&file_versions);
298 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
299 if (havename && strcasecmp(iterator->file, argv[3]))
302 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
305 ast_cli(fd, FORMAT, iterator->file, iterator->version);
310 AST_LIST_UNLOCK(&file_versions);
312 ast_cli(fd, "%d files listed.\n", count_files);
318 return RESULT_SUCCESS;
322 static char *complete_show_version_files(char *line, char *word, int pos, int state)
324 struct file_version *find;
327 int matchlen = strlen(word);
332 AST_LIST_LOCK(&file_versions);
333 AST_LIST_TRAVERSE(&file_versions, find, list) {
334 if (!strncasecmp(word, find->file, matchlen)) {
335 if (++which > state) {
336 ret = strdup(find->file);
341 AST_LIST_UNLOCK(&file_versions);
345 #endif /* ! LOW_MEMORY */
347 int ast_register_atexit(void (*func)(void))
350 struct ast_atexit *ae;
351 ast_unregister_atexit(func);
352 ae = malloc(sizeof(struct ast_atexit));
353 ast_mutex_lock(&atexitslock);
355 memset(ae, 0, sizeof(struct ast_atexit));
361 ast_mutex_unlock(&atexitslock);
365 void ast_unregister_atexit(void (*func)(void))
367 struct ast_atexit *ae, *prev = NULL;
368 ast_mutex_lock(&atexitslock);
371 if (ae->func == func) {
373 prev->next = ae->next;
381 ast_mutex_unlock(&atexitslock);
384 static int fdprint(int fd, const char *s)
386 return write(fd, s, strlen(s) + 1);
389 /*! NULL handler so we can collect the child exit status */
390 static void null_sig_handler(int signal)
395 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
396 static unsigned int safe_system_level = 0;
397 static void *safe_system_prev_handler;
399 int ast_safe_system(const char *s)
404 struct rusage rusage;
408 /* keep track of how many ast_safe_system() functions
409 are running at this moment
411 ast_mutex_lock(&safe_system_lock);
412 level = safe_system_level++;
414 /* only replace the handler if it has not already been done */
416 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
418 ast_mutex_unlock(&safe_system_lock);
423 /* Close file descriptors and launch system command */
424 for (x = STDERR_FILENO + 1; x < 4096; x++)
426 execl("/bin/sh", "/bin/sh", "-c", s, NULL);
428 } else if (pid > 0) {
430 res = wait4(pid, &status, 0, &rusage);
432 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
434 } else if (errno != EINTR)
438 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
442 ast_mutex_lock(&safe_system_lock);
443 level = --safe_system_level;
445 /* only restore the handler if we are the last one */
447 signal(SIGCHLD, safe_system_prev_handler);
449 ast_mutex_unlock(&safe_system_lock);
455 * write the string to all attached console clients
457 static void ast_network_puts(const char *string)
460 for (x=0;x<AST_MAX_CONNECTS; x++) {
461 if (consoles[x].fd > -1)
462 fdprint(consoles[x].p[1], string);
467 * write the string to the console, and all attached
470 void ast_console_puts(const char *string)
472 fputs(string, stdout);
474 ast_network_puts(string);
477 static void network_verboser(const char *s, int pos, int replace, int complete)
481 char *t = alloca(strlen(s) + 2);
483 sprintf(t, "\r%s", s);
487 ast_log(LOG_ERROR, "Out of memory\n");
496 static pthread_t lthread;
498 static void *netconsole(void *vconsole)
500 struct console *con = vconsole;
501 char hostname[MAXHOSTNAMELEN]="";
504 struct pollfd fds[2];
506 if (gethostname(hostname, sizeof(hostname)-1))
507 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
508 snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
509 fdprint(con->fd, tmp);
512 fds[0].events = POLLIN;
514 fds[1].fd = con->p[0];
515 fds[1].events = POLLIN;
518 res = poll(fds, 2, -1);
521 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
524 if (fds[0].revents) {
525 res = read(con->fd, tmp, sizeof(tmp));
530 ast_cli_command(con->fd, tmp);
532 if (fds[1].revents) {
533 res = read(con->p[0], tmp, sizeof(tmp));
535 ast_log(LOG_ERROR, "read returned %d\n", res);
538 res = write(con->fd, tmp, res);
543 if (option_verbose > 2)
544 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
553 static void *listener(void *unused)
555 struct sockaddr_un sunaddr;
560 struct pollfd fds[1];
562 pthread_attr_init(&attr);
563 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
567 fds[0].fd = ast_socket;
568 fds[0].events= POLLIN;
569 s = poll(fds, 1, -1);
572 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
575 len = sizeof(sunaddr);
576 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
579 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
581 for (x=0;x<AST_MAX_CONNECTS;x++) {
582 if (consoles[x].fd < 0) {
583 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
584 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
586 fdprint(s, "Server failed to create pipe\n");
590 flags = fcntl(consoles[x].p[1], F_GETFL);
591 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
593 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
594 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
596 fdprint(s, "Server failed to spawn thread\n");
602 if (x >= AST_MAX_CONNECTS) {
603 fdprint(s, "No more connections allowed\n");
604 ast_log(LOG_WARNING, "No more connections allowed\n");
606 } else if (consoles[x].fd > -1) {
607 if (option_verbose > 2)
608 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
615 static int ast_makesocket(void)
617 struct sockaddr_un sunaddr;
623 for (x = 0; x < AST_MAX_CONNECTS; x++)
625 unlink(ast_config_AST_SOCKET);
626 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
627 if (ast_socket < 0) {
628 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
631 memset(&sunaddr, 0, sizeof(sunaddr));
632 sunaddr.sun_family = AF_LOCAL;
633 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
634 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
636 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
641 res = listen(ast_socket, 2);
643 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
648 ast_register_verbose(network_verboser);
649 ast_pthread_create(<hread, NULL, listener, NULL);
651 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
653 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
654 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
660 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
662 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
663 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
669 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
670 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
672 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
675 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
677 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
678 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
684 static int ast_tryconnect(void)
686 struct sockaddr_un sunaddr;
688 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
689 if (ast_consock < 0) {
690 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
693 memset(&sunaddr, 0, sizeof(sunaddr));
694 sunaddr.sun_family = AF_LOCAL;
695 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
696 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
706 Called by soft_hangup to interrupt the poll, read, or other
707 system call. We don't actually need to do anything though.
708 Remember: Cannot EVER ast_log from within a signal handler
709 SLD: seems to be some pthread activity relating to the printf anyway:
710 which is leading to a deadlock?
712 static void urg_handler(int num)
715 if (option_debug > 2)
716 printf("-- Asterisk Urgent handler\n");
718 signal(num, urg_handler);
722 static void hup_handler(int num)
724 if (option_verbose > 1)
725 printf("Received HUP signal -- Reloading configs\n");
727 execvp(_argv[0], _argv);
728 /* XXX This could deadlock XXX */
729 ast_module_reload(NULL);
730 signal(num, hup_handler);
733 static void child_handler(int sig)
735 /* Must not ever ast_log or ast_verbose within signal handler */
739 * Reap all dead children -- not just one
741 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
743 if (n == 0 && option_debug)
744 printf("Huh? Child handler, but nobody there?\n");
745 signal(sig, child_handler);
748 /*! Set an X-term or screen title */
749 static void set_title(char *text)
751 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
752 fprintf(stdout, "\033]2;%s\007", text);
755 static void set_icon(char *text)
757 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
758 fprintf(stdout, "\033]1;%s\007", text);
761 /*! We set ourselves to a high priority, that we might pre-empt everything
762 else. If your PBX has heavy activity on it, this is a good thing. */
763 int ast_set_priority(int pri)
765 struct sched_param sched;
766 memset(&sched, 0, sizeof(sched));
769 sched.sched_priority = 10;
770 if (sched_setscheduler(0, SCHED_RR, &sched)) {
771 ast_log(LOG_WARNING, "Unable to set high priority\n");
775 ast_verbose("Set to realtime thread\n");
777 sched.sched_priority = 0;
778 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
779 ast_log(LOG_WARNING, "Unable to set normal priority\n");
785 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
786 ast_log(LOG_WARNING, "Unable to set high priority\n");
790 ast_verbose("Set to high priority\n");
792 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
793 ast_log(LOG_WARNING, "Unable to set normal priority\n");
801 static void ast_run_atexits(void)
803 struct ast_atexit *ae;
804 ast_mutex_lock(&atexitslock);
811 ast_mutex_unlock(&atexitslock);
814 static void quit_handler(int num, int nice, int safeshutdown, int restart)
816 char filename[80] = "";
819 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
820 ast_cdr_engine_term();
824 /* Begin shutdown routine, hanging up active channels */
825 ast_begin_shutdown(1);
826 if (option_verbose && ast_opt_console)
827 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
831 /* Wait up to 15 seconds for all channels to go away */
834 if (!ast_active_channels())
838 /* Sleep 1/10 of a second */
843 ast_begin_shutdown(0);
844 if (option_verbose && ast_opt_console)
845 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
847 if (!ast_active_channels())
856 if (option_verbose && ast_opt_console)
857 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
861 if (ast_opt_console || ast_opt_remote) {
863 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
864 if (!ast_strlen_zero(filename))
865 ast_el_write_history(filename);
869 history_end(el_hist);
872 ast_verbose("Executing last minute cleanups\n");
875 if (option_verbose && ast_opt_console)
876 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
877 else if (option_debug)
878 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
879 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
880 if (ast_socket > -1) {
884 if (ast_consock > -1)
887 unlink(ast_config_AST_SOCKET);
889 unlink(ast_config_AST_PID);
892 if (option_verbose || ast_opt_console)
893 ast_verbose("Preparing for Asterisk restart...\n");
894 /* Mark all FD's for closing on exec */
895 for (x=3;x<32768;x++) {
896 fcntl(x, F_SETFD, FD_CLOEXEC);
898 if (option_verbose || ast_opt_console)
899 ast_verbose("Restarting Asterisk NOW...\n");
905 /* If there is a consolethread running send it a SIGHUP
906 so it can execvp, otherwise we can do it ourselves */
907 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
908 pthread_kill(consolethread, SIGHUP);
909 /* Give the signal handler some time to complete */
912 execvp(_argv[0], _argv);
921 static void __quit_handler(int num)
923 quit_handler(num, 0, 1, 0);
926 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
929 if (!strncmp(s, cmp, strlen(cmp))) {
931 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
937 static void console_verboser(const char *s, int pos, int replace, int complete)
941 /* Return to the beginning of the line */
943 fprintf(stdout, "\r");
944 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
945 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
946 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
947 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
951 fputs(c + pos,stdout);
953 fputs(s + pos,stdout);
956 /* Wake up a poll()ing console */
957 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
958 pthread_kill(consolethread, SIGURG);
962 static int ast_all_zeros(char *s)
972 static void consolehandler(char *s)
976 /* Called when readline data is available */
977 if (s && !ast_all_zeros(s))
978 ast_el_add_history(s);
979 /* Give the console access to the shell */
981 /* The real handler for bang */
984 ast_safe_system(s+1);
986 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
988 ast_cli_command(STDOUT_FILENO, s);
990 fprintf(stdout, "\nUse \"quit\" to exit\n");
993 static int remoteconsolehandler(char *s)
996 /* Called when readline data is available */
997 if (s && !ast_all_zeros(s))
998 ast_el_add_history(s);
999 /* Give the console access to the shell */
1001 /* The real handler for bang */
1004 ast_safe_system(s+1);
1006 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1009 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1010 (s[4] == '\0' || isspace(s[4]))) {
1011 quit_handler(0, 0, 0, 0);
1015 fprintf(stdout, "\nUse \"quit\" to exit\n");
1020 static char abort_halt_help[] =
1021 "Usage: abort shutdown\n"
1022 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1023 " call operations.\n";
1025 static char shutdown_now_help[] =
1027 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1029 static char shutdown_gracefully_help[] =
1030 "Usage: stop gracefully\n"
1031 " Causes Asterisk to not accept new calls, and exit when all\n"
1032 " active calls have terminated normally.\n";
1034 static char shutdown_when_convenient_help[] =
1035 "Usage: stop when convenient\n"
1036 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1038 static char restart_now_help[] =
1039 "Usage: restart now\n"
1040 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1043 static char restart_gracefully_help[] =
1044 "Usage: restart gracefully\n"
1045 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1046 " restart when all active calls have ended.\n";
1048 static char restart_when_convenient_help[] =
1049 "Usage: restart when convenient\n"
1050 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1052 static char bang_help[] =
1053 "Usage: !<command>\n"
1054 " Executes a given shell command\n";
1056 static char show_warranty_help[] =
1057 "Usage: show warranty\n"
1058 " Shows the warranty (if any) for this copy of Asterisk.\n";
1060 static char show_license_help[] =
1061 "Usage: show license\n"
1062 " Shows the license(s) for this copy of Asterisk.\n";
1065 static int handle_quit(int fd, int argc, char *argv[])
1068 return RESULT_SHOWUSAGE;
1069 quit_handler(0, 0, 1, 0);
1070 return RESULT_SUCCESS;
1074 static int handle_shutdown_now(int fd, int argc, char *argv[])
1077 return RESULT_SHOWUSAGE;
1078 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1079 return RESULT_SUCCESS;
1082 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1085 return RESULT_SHOWUSAGE;
1086 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1087 return RESULT_SUCCESS;
1090 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1093 return RESULT_SHOWUSAGE;
1094 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1095 return RESULT_SUCCESS;
1098 static int handle_restart_now(int fd, int argc, char *argv[])
1101 return RESULT_SHOWUSAGE;
1102 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1103 return RESULT_SUCCESS;
1106 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1109 return RESULT_SHOWUSAGE;
1110 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1111 return RESULT_SUCCESS;
1114 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1117 return RESULT_SHOWUSAGE;
1118 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1119 return RESULT_SUCCESS;
1122 static int handle_abort_halt(int fd, int argc, char *argv[])
1125 return RESULT_SHOWUSAGE;
1126 ast_cancel_shutdown();
1128 return RESULT_SUCCESS;
1131 static int handle_bang(int fd, int argc, char *argv[])
1133 return RESULT_SUCCESS;
1135 static const char *warranty_lines[] = {
1139 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1140 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1141 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1142 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1143 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1144 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1145 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1146 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1147 "REPAIR OR CORRECTION.\n",
1149 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1150 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1151 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1152 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1153 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1154 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1155 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1156 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1157 "POSSIBILITY OF SUCH DAMAGES.\n",
1160 static int show_warranty(int fd, int argc, char *argv[])
1164 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1165 ast_cli(fd, (char *) warranty_lines[x]);
1167 return RESULT_SUCCESS;
1170 static const char *license_lines[] = {
1172 "This program is free software; you can redistribute it and/or modify\n",
1173 "it under the terms of the GNU General Public License version 2 as\n",
1174 "published by the Free Software Foundation.\n",
1176 "This program also contains components licensed under other licenses.\n",
1179 "This program is distributed in the hope that it will be useful,\n",
1180 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1181 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1182 "GNU General Public License for more details.\n",
1184 "You should have received a copy of the GNU General Public License\n",
1185 "along with this program; if not, write to the Free Software\n",
1186 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1189 static int show_license(int fd, int argc, char *argv[])
1193 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1194 ast_cli(fd, (char *) license_lines[x]);
1196 return RESULT_SUCCESS;
1199 #define ASTERISK_PROMPT "*CLI> "
1201 #define ASTERISK_PROMPT2 "%s*CLI> "
1203 static struct ast_cli_entry core_cli[] = {
1204 { { "abort", "halt", NULL }, handle_abort_halt,
1205 "Cancel a running halt", abort_halt_help },
1206 { { "stop", "now", NULL }, handle_shutdown_now,
1207 "Shut down Asterisk immediately", shutdown_now_help },
1208 { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1209 "Gracefully shut down Asterisk", shutdown_gracefully_help },
1210 { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1211 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1212 { { "restart", "now", NULL }, handle_restart_now,
1213 "Restart Asterisk immediately", restart_now_help },
1214 { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1215 "Restart Asterisk gracefully", restart_gracefully_help },
1216 { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1217 "Restart Asterisk at empty call volume", restart_when_convenient_help },
1218 { { "show", "warranty", NULL }, show_warranty,
1219 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
1220 { { "show", "license", NULL }, show_license,
1221 "Show the license(s) for this copy of Asterisk", show_license_help },
1222 { { "!", NULL }, handle_bang,
1223 "Execute a shell command", bang_help },
1224 #if !defined(LOW_MEMORY)
1225 { { "show", "version", "files", NULL }, handle_show_version_files,
1226 "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1227 #endif /* ! LOW_MEMORY */
1230 static int ast_el_read_char(EditLine *el, char *cp)
1234 struct pollfd fds[2];
1241 fds[0].fd = ast_consock;
1242 fds[0].events = POLLIN;
1243 if (!ast_opt_exec) {
1244 fds[1].fd = STDIN_FILENO;
1245 fds[1].events = POLLIN;
1248 res = poll(fds, max, -1);
1252 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1256 if (!ast_opt_exec && fds[1].revents) {
1257 num_read = read(STDIN_FILENO, cp, 1);
1263 if (fds[0].revents) {
1264 res = read(ast_consock, buf, sizeof(buf) - 1);
1265 /* if the remote side disappears exit */
1267 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1268 if (!ast_opt_reconnect) {
1269 quit_handler(0, 0, 0, 0);
1272 int reconnects_per_second = 20;
1273 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1274 for (tries=0;tries<30 * reconnects_per_second;tries++) {
1275 if (ast_tryconnect()) {
1276 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1277 printf(term_quit());
1281 usleep(1000000 / reconnects_per_second);
1284 if (tries >= 30 * reconnects_per_second) {
1285 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1286 quit_handler(0, 0, 0, 0);
1293 if (!ast_opt_exec && !lastpos)
1294 write(STDOUT_FILENO, "\r", 1);
1295 write(STDOUT_FILENO, buf, res);
1296 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1309 static char *cli_prompt(EditLine *el)
1311 static char prompt[200];
1316 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1317 char *t = pfmt, *p = prompt;
1318 memset(prompt, 0, sizeof(prompt));
1319 while (*t != '\0' && *p < sizeof(prompt)) {
1321 char hostname[MAXHOSTNAMELEN]="";
1328 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1332 case 'C': /* color */
1334 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1335 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1337 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1338 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1342 /* If the color has been reset correctly, then there's no need to reset it later */
1343 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1349 case 'd': /* date */
1350 memset(&tm, 0, sizeof(struct tm));
1352 if (localtime_r(&ts, &tm)) {
1353 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1356 case 'h': /* hostname */
1357 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1358 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1360 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1363 case 'H': /* short hostname */
1364 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1365 for (i=0;i<sizeof(hostname);i++) {
1366 if (hostname[i] == '.') {
1371 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1373 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1377 case 'l': /* load avg */
1379 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1380 float avg1, avg2, avg3;
1381 int actproc, totproc, npid, which;
1382 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1383 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1384 if (sscanf(t, "%d", &which) == 1) {
1387 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1390 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1393 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1396 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1399 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1406 case 't': /* time */
1407 memset(&tm, 0, sizeof(struct tm));
1409 if (localtime_r(&ts, &tm)) {
1410 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1413 case '#': /* process console or remote? */
1414 if (!ast_opt_remote) {
1415 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1417 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1420 case '%': /* literal % */
1421 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1423 case '\0': /* % is last character - prevent bug */
1427 while (*p != '\0') {
1438 /* Force colors back to normal at end */
1439 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1440 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1441 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1443 strncat(p, term_code, sizeof(term_code));
1446 } else if (remotehostname)
1447 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1449 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1454 static char **ast_el_strtoarr(char *buf)
1456 char **match_list = NULL, *retstr;
1457 size_t match_list_len;
1461 while ( (retstr = strsep(&buf, " ")) != NULL) {
1463 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1465 if (matches + 1 >= match_list_len) {
1466 match_list_len <<= 1;
1467 match_list = realloc(match_list, match_list_len * sizeof(char *));
1470 match_list[matches++] = strdup(retstr);
1474 return (char **) NULL;
1476 if (matches>= match_list_len)
1477 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
1479 match_list[matches] = (char *) NULL;
1484 static int ast_el_sort_compare(const void *i1, const void *i2)
1488 s1 = ((char **)i1)[0];
1489 s2 = ((char **)i2)[0];
1491 return strcasecmp(s1, s2);
1494 static int ast_cli_display_match_list(char **matches, int len, int max)
1496 int i, idx, limit, count;
1497 int screenwidth = 0;
1498 int numoutput = 0, numoutputline = 0;
1500 screenwidth = ast_get_termcols(STDOUT_FILENO);
1502 /* find out how many entries can be put on one line, with two spaces between strings */
1503 limit = screenwidth / (max + 2);
1507 /* how many lines of output */
1508 count = len / limit;
1509 if (count * limit < len)
1514 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1516 for (; count > 0; count--) {
1518 for (i=0; i < limit && matches[idx]; i++, idx++) {
1520 /* Don't print dupes */
1521 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1524 matches[idx] = NULL;
1530 fprintf(stdout, "%-*s ", max, matches[idx]);
1532 matches[idx] = NULL;
1534 if (numoutputline > 0)
1535 fprintf(stdout, "\n");
1542 static char *cli_complete(EditLine *el, int ch)
1548 int retval = CC_ERROR;
1552 LineInfo *lf = (LineInfo *)el_line(el);
1554 *(char *)lf->cursor = '\0';
1555 ptr = (char *)lf->cursor;
1557 while (ptr > lf->buffer) {
1558 if (isspace(*ptr)) {
1566 len = lf->cursor - ptr;
1568 if (ast_opt_remote) {
1569 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1570 fdprint(ast_consock, buf);
1571 res = read(ast_consock, buf, sizeof(buf));
1573 nummatches = atoi(buf);
1575 if (nummatches > 0) {
1577 int mlen = 0, maxmbuf = 2048;
1578 /* Start with a 2048 byte buffer */
1579 mbuf = malloc(maxmbuf);
1581 return (char *)(CC_ERROR);
1582 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1583 fdprint(ast_consock, buf);
1586 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1587 if (mlen + 1024 > maxmbuf) {
1588 /* Every step increment buffer 1024 bytes */
1590 mbuf = realloc(mbuf, maxmbuf);
1592 return (char *)(CC_ERROR);
1594 /* Only read 1024 bytes at a time */
1595 res = read(ast_consock, mbuf + mlen, 1024);
1601 matches = ast_el_strtoarr(mbuf);
1604 matches = (char **) NULL;
1606 char **p, *oldbuf=NULL;
1608 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1609 for (p = matches; p && *p; p++) {
1610 if (!oldbuf || strcmp(*p,oldbuf))
1618 int matches_num, maxlen, match_len;
1620 if (matches[0][0] != '\0') {
1621 el_deletestr(el, (int) len);
1622 el_insertstr(el, matches[0]);
1623 retval = CC_REFRESH;
1626 if (nummatches == 1) {
1627 /* Found an exact match */
1628 el_insertstr(el, " ");
1629 retval = CC_REFRESH;
1631 /* Must be more than one match */
1632 for (i=1, maxlen=0; matches[i]; i++) {
1633 match_len = strlen(matches[i]);
1634 if (match_len > maxlen)
1637 matches_num = i - 1;
1638 if (matches_num >1) {
1639 fprintf(stdout, "\n");
1640 ast_cli_display_match_list(matches, nummatches, maxlen);
1641 retval = CC_REDISPLAY;
1643 el_insertstr(el," ");
1644 retval = CC_REFRESH;
1650 return (char *)(long)retval;
1653 static int ast_el_initialize(void)
1656 char *editor = getenv("AST_EDITOR");
1660 if (el_hist != NULL)
1661 history_end(el_hist);
1663 el = el_init("asterisk", stdin, stdout, stderr);
1664 el_set(el, EL_PROMPT, cli_prompt);
1666 el_set(el, EL_EDITMODE, 1);
1667 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1668 el_hist = history_init();
1669 if (!el || !el_hist)
1672 /* setup history with 100 entries */
1673 history(el_hist, &ev, H_SETSIZE, 100);
1675 el_set(el, EL_HIST, history, el_hist);
1677 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1678 /* Bind <tab> to command completion */
1679 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1680 /* Bind ? to command completion */
1681 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1682 /* Bind ^D to redisplay */
1683 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1688 static int ast_el_add_history(char *buf)
1692 if (el_hist == NULL || el == NULL)
1693 ast_el_initialize();
1694 if (strlen(buf) > 256)
1696 return (history(el_hist, &ev, H_ENTER, buf));
1699 static int ast_el_write_history(char *filename)
1703 if (el_hist == NULL || el == NULL)
1704 ast_el_initialize();
1706 return (history(el_hist, &ev, H_SAVE, filename));
1709 static int ast_el_read_history(char *filename)
1715 if (el_hist == NULL || el == NULL)
1716 ast_el_initialize();
1718 if ((f = fopen(filename, "r")) == NULL)
1722 fgets(buf, sizeof(buf), f);
1723 if (!strcmp(buf, "_HiStOrY_V2_\n"))
1725 if (ast_all_zeros(buf))
1727 if ((ret = ast_el_add_history(buf)) == -1)
1735 static void ast_remotecontrol(char * data)
1739 char filename[80] = "";
1750 read(ast_consock, buf, sizeof(buf));
1752 write(ast_consock, data, strlen(data) + 1);
1754 hostname = strsep(&stringp, "/");
1755 cpid = strsep(&stringp, "/");
1756 version = strsep(&stringp, "\n");
1758 version = "<Version Unknown>";
1760 strsep(&stringp, ".");
1765 snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1766 fdprint(ast_consock, tmp);
1767 snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
1768 fdprint(ast_consock, tmp);
1769 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1770 remotehostname = hostname;
1772 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1773 if (el_hist == NULL || el == NULL)
1774 ast_el_initialize();
1776 el_set(el, EL_GETCFN, ast_el_read_char);
1778 if (!ast_strlen_zero(filename))
1779 ast_el_read_history(filename);
1781 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
1783 struct pollfd fds[0];
1784 fds[0].fd = ast_consock;
1785 fds[0].events = POLLIN;
1787 while(poll(fds, 1, 100) > 0) {
1788 ast_el_read_char(el, &tempchar);
1793 ebuf = (char *)el_gets(el, &num);
1795 if (!ast_strlen_zero(ebuf)) {
1796 if (ebuf[strlen(ebuf)-1] == '\n')
1797 ebuf[strlen(ebuf)-1] = '\0';
1798 if (!remoteconsolehandler(ebuf)) {
1799 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1801 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1807 printf("\nDisconnected from Asterisk server\n");
1810 static int show_version(void)
1812 printf("Asterisk " ASTERISK_VERSION "\n");
1816 static int show_cli_help(void) {
1817 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005, Digium, Inc. and others.\n");
1818 printf("Usage: asterisk [OPTIONS]\n");
1819 printf("Valid Options:\n");
1820 printf(" -V Display version number and exit\n");
1821 printf(" -C <configfile> Use an alternate configuration file\n");
1822 printf(" -G <group> Run as a group other than the caller\n");
1823 printf(" -U <user> Run as a user other than the caller\n");
1824 printf(" -c Provide console CLI\n");
1825 printf(" -d Enable extra debugging\n");
1826 printf(" -f Do not fork\n");
1827 printf(" -g Dump core in case of a crash\n");
1828 printf(" -h This help screen\n");
1829 printf(" -i Initialize crypto keys at startup\n");
1830 printf(" -n Disable console colorization\n");
1831 printf(" -p Run as pseudo-realtime thread\n");
1832 printf(" -q Quiet mode (suppress output)\n");
1833 printf(" -r Connect to Asterisk on this machine\n");
1834 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
1835 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
1836 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
1837 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
1838 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
1843 static void ast_readconfig(void) {
1844 struct ast_config *cfg;
1845 struct ast_variable *v;
1846 char *config = AST_CONFIG_FILE;
1848 if (ast_opt_override_config) {
1849 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
1851 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
1853 cfg = ast_config_load(config);
1856 /* init with buildtime config */
1857 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
1858 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
1859 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_VAR_DIR));
1860 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
1861 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
1862 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
1863 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
1864 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
1865 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
1866 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
1867 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
1868 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
1870 /* no asterisk.conf? no problem, use buildtime config! */
1874 v = ast_variable_browse(cfg, "files");
1876 if (!strcasecmp(v->name, "astctlpermissions")) {
1877 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
1878 } else if (!strcasecmp(v->name, "astctlowner")) {
1879 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
1880 } else if (!strcasecmp(v->name, "astctlgroup")) {
1881 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
1882 } else if (!strcasecmp(v->name, "astctl")) {
1883 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
1887 v = ast_variable_browse(cfg, "directories");
1889 if (!strcasecmp(v->name, "astetcdir")) {
1890 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
1891 } else if (!strcasecmp(v->name, "astspooldir")) {
1892 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
1893 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
1894 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1895 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
1896 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/%s", v->value, "astdb");
1897 } else if (!strcasecmp(v->name, "astlogdir")) {
1898 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
1899 } else if (!strcasecmp(v->name, "astagidir")) {
1900 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
1901 } else if (!strcasecmp(v->name, "astrundir")) {
1902 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
1903 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
1904 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
1905 } else if (!strcasecmp(v->name, "astmoddir")) {
1906 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
1910 v = ast_variable_browse(cfg, "options");
1912 /* verbose level (-v at startup) */
1913 if (!strcasecmp(v->name, "verbose")) {
1914 option_verbose = atoi(v->value);
1915 /* whether or not to force timestamping. (-T at startup) */
1916 } else if (!strcasecmp(v->name, "timestamp")) {
1917 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
1918 /* whether or not to support #exec in config files */
1919 } else if (!strcasecmp(v->name, "execincludes")) {
1920 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
1921 /* debug level (-d at startup) */
1922 } else if (!strcasecmp(v->name, "debug")) {
1924 if (sscanf(v->value, "%d", &option_debug) != 1) {
1925 option_debug = ast_true(v->value);
1927 /* Disable forking (-f at startup) */
1928 } else if (!strcasecmp(v->name, "nofork")) {
1929 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
1930 /* Run quietly (-q at startup ) */
1931 } else if (!strcasecmp(v->name, "quiet")) {
1932 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
1933 /* Run as console (-c at startup, implies nofork) */
1934 } else if (!strcasecmp(v->name, "console")) {
1935 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
1936 /* Run with highg priority if the O/S permits (-p at startup) */
1937 } else if (!strcasecmp(v->name, "highpriority")) {
1938 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
1939 /* Initialize RSA auth keys (IAX2) (-i at startup) */
1940 } else if (!strcasecmp(v->name, "initcrypto")) {
1941 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
1942 /* Disable ANSI colors for console (-c at startup) */
1943 } else if (!strcasecmp(v->name, "nocolor")) {
1944 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
1945 /* Disable some usage warnings for picky people :p */
1946 } else if (!strcasecmp(v->name, "dontwarn")) {
1947 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
1948 /* Dump core in case of crash (-g) */
1949 } else if (!strcasecmp(v->name, "dumpcore")) {
1950 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
1951 /* Cache recorded sound files to another directory during recording */
1952 } else if (!strcasecmp(v->name, "cache_record_files")) {
1953 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
1954 /* Specify cache directory */
1955 } else if (!strcasecmp(v->name, "record_cache_dir")) {
1956 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
1957 /* Build transcode paths via SLINEAR, instead of directly */
1958 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
1959 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
1960 /* Transmit SLINEAR silence while a channel is being recorded */
1961 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
1962 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
1963 } else if (!strcasecmp(v->name, "maxcalls")) {
1964 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
1965 option_maxcalls = 0;
1967 } else if (!strcasecmp(v->name, "maxload")) {
1970 if (getloadavg(test, 1) == -1) {
1971 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
1972 option_maxload = 0.0;
1973 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
1974 option_maxload = 0.0;
1976 /* What user to run as */
1977 } else if (!strcasecmp(v->name, "runuser")) {
1978 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
1979 /* What group to run as */
1980 } else if (!strcasecmp(v->name, "rungroup")) {
1981 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
1985 ast_config_destroy(cfg);
1988 int main(int argc, char *argv[])
1991 char filename[80] = "";
1992 char hostname[MAXHOSTNAMELEN]="";
1999 int is_child_of_nonroot=0;
2001 char *runuser=NULL, *rungroup=NULL;
2003 /* Remember original args for restart */
2004 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2005 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2006 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2008 for (x=0;x<argc;x++)
2012 /* if the progname is rasterisk consider it a remote console */
2013 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2014 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2016 if (gethostname(hostname, sizeof(hostname)-1))
2017 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2018 ast_mainpid = getpid();
2024 /* When Asterisk restarts after it has dropped the root privileges,
2025 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2027 if (getenv("ASTERISK_ALREADY_NONROOT"))
2028 is_child_of_nonroot=1;
2030 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2031 /* Check if we're root */
2034 ast_log(LOG_ERROR, "Must be run as root\n");
2038 /* Check for options */
2039 while((c=getopt(argc, argv, "tThfdvVqprRgcinx:U:G:C:L:M:")) != -1) {
2043 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2046 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2049 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2052 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2055 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2058 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2061 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2065 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2068 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2069 option_maxcalls = 0;
2072 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2073 option_maxload = 0.0;
2076 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2079 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2082 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2085 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2089 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2090 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2093 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2096 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2115 /* For remote connections, change the name of the remote connection.
2116 * We do this for the benefit of init scripts (which need to know if/when
2117 * the main asterisk process has died yet). */
2118 if (ast_opt_remote) {
2119 strcpy(argv[0], "rasterisk");
2120 for (x = 1; x < argc; x++) {
2121 argv[x] = argv[0] + 10;
2125 if (ast_opt_dump_core) {
2127 memset(&l, 0, sizeof(l));
2128 l.rlim_cur = RLIM_INFINITY;
2129 l.rlim_max = RLIM_INFINITY;
2130 if (setrlimit(RLIMIT_CORE, &l)) {
2131 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2135 if (ast_opt_console && !option_verbose)
2136 ast_verbose("[ Reading Master Configuration ]");
2139 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2140 rungroup = ast_config_AST_RUN_GROUP;
2141 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2142 runuser = ast_config_AST_RUN_USER;
2145 if (!is_child_of_nonroot)
2146 ast_set_priority(ast_opt_high_priority);
2148 if (!is_child_of_nonroot && rungroup) {
2150 gr = getgrnam(rungroup);
2152 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2155 if (setgid(gr->gr_gid)) {
2156 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", gr->gr_gid, rungroup);
2159 if (setgroups(0, NULL)) {
2160 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2164 ast_verbose("Running as group '%s'\n", rungroup);
2167 if (!is_child_of_nonroot && runuser) {
2169 pw = getpwnam(runuser);
2171 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2174 if (!ast_strlen_zero(rungroup))
2175 if (initgroups(pw->pw_name, pw->pw_gid)) {
2176 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2180 if (setuid(pw->pw_uid)) {
2181 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", pw->pw_uid, runuser);
2184 setenv("ASTERISK_ALREADY_NONROOT","yes",1);
2186 ast_verbose("Running as user '%s'\n", runuser);
2189 #endif /* __CYGWIN__ */
2195 if (ast_opt_console && !option_verbose)
2196 ast_verbose("[ Initializing Custom Configuration Options ]");
2197 /* custom config setup */
2198 register_config_cli();
2202 if (ast_opt_console) {
2203 if (el_hist == NULL || el == NULL)
2204 ast_el_initialize();
2206 if (!ast_strlen_zero(filename))
2207 ast_el_read_history(filename);
2210 if (ast_tryconnect()) {
2211 /* One is already running */
2212 if (ast_opt_remote) {
2214 ast_remotecontrol(xarg);
2215 quit_handler(0, 0, 0, 0);
2218 printf(term_quit());
2219 ast_register_verbose(console_verboser);
2221 ast_remotecontrol(NULL);
2222 quit_handler(0, 0, 0, 0);
2225 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2226 printf(term_quit());
2229 } else if (ast_opt_remote || ast_opt_exec) {
2230 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n",ast_config_AST_SOCKET);
2231 printf(term_quit());
2234 /* Blindly write pid file since we couldn't connect */
2235 unlink(ast_config_AST_PID);
2236 f = fopen(ast_config_AST_PID, "w");
2238 fprintf(f, "%d\n", getpid());
2241 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2243 if (!option_verbose && !option_debug && !ast_opt_no_fork && !ast_opt_console) {
2245 /* Blindly re-write pid file since we are forking */
2246 unlink(ast_config_AST_PID);
2247 f = fopen(ast_config_AST_PID, "w");
2249 fprintf(f, "%d\n", getpid());
2252 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2255 /* Test recursive mutex locking. */
2256 if (test_for_thread_safety())
2257 ast_verbose("Warning! Asterisk is not thread safe.\n");
2261 sigaddset(&sigs, SIGHUP);
2262 sigaddset(&sigs, SIGTERM);
2263 sigaddset(&sigs, SIGINT);
2264 sigaddset(&sigs, SIGPIPE);
2265 sigaddset(&sigs, SIGWINCH);
2266 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2267 if (ast_opt_console || option_verbose || ast_opt_remote)
2268 ast_register_verbose(console_verboser);
2269 /* Print a welcome message if desired */
2270 if (option_verbose || ast_opt_console) {
2273 if (ast_opt_console && !option_verbose)
2274 ast_verbose("[ Booting...");
2276 signal(SIGURG, urg_handler);
2277 signal(SIGINT, __quit_handler);
2278 signal(SIGTERM, __quit_handler);
2279 signal(SIGHUP, hup_handler);
2280 signal(SIGCHLD, child_handler);
2281 signal(SIGPIPE, SIG_IGN);
2283 /* ensure that the random number generators are seeded with a different value every time
2286 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2287 srandom((unsigned int) getpid() + (unsigned int) time(NULL));
2289 if (init_logger()) {
2290 printf(term_quit());
2293 if (dnsmgr_init()) {
2294 printf(term_quit());
2297 /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2298 if (load_modules(1)) {
2299 printf(term_quit());
2302 ast_channels_init();
2303 if (init_manager()) {
2304 printf(term_quit());
2307 if (ast_cdr_engine_init()) {
2308 printf(term_quit());
2311 if (ast_device_state_engine_init()) {
2312 printf(term_quit());
2316 if (ast_image_init()) {
2317 printf(term_quit());
2320 if (ast_file_init()) {
2321 printf(term_quit());
2325 printf(term_quit());
2328 if (load_modules(0)) {
2329 printf(term_quit());
2332 if (init_framer()) {
2333 printf(term_quit());
2337 printf(term_quit());
2340 if (ast_enum_init()) {
2341 printf(term_quit());
2345 dnsmgr_start_refresh();
2348 /* This should no longer be necessary */
2349 /* sync cust config and reload some internals in case a custom config handler binded to them */
2350 read_ast_cust_config();
2358 /* We might have the option of showing a console, but for now just
2360 if (ast_opt_console && !option_verbose)
2361 ast_verbose(" ]\n");
2362 if (option_verbose || ast_opt_console)
2363 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2364 if (ast_opt_no_fork)
2365 consolethread = pthread_self();
2366 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2367 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2368 #ifdef __AST_DEBUG_MALLOC
2371 time(&ast_startuptime);
2372 ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2373 if (ast_opt_console) {
2374 /* Console stuff now... */
2375 /* Register our quit function */
2377 set_icon("Asterisk");
2378 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
2382 buf = (char *)el_gets(el, &num);
2384 if (buf[strlen(buf)-1] == '\n')
2385 buf[strlen(buf)-1] = '\0';
2387 consolehandler((char *)buf);
2389 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2390 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2391 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2393 fd = open("/dev/null", O_RDWR);
2395 dup2(fd, STDOUT_FILENO);
2396 dup2(fd, STDIN_FILENO);
2398 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2406 for(;;) { /* apparently needed for the MACos */
2407 struct pollfd p = { -1 /* no descriptor */, 0, 0 };