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
25 * \arg \ref ConfigFiles
27 * \section copyright Copyright and author
29 * Copyright (C) 1999 - 2005, Digium, Inc.
30 * Asterisk is a trade mark registered by Digium, Inc.
32 * \author Mark Spencer <markster@digium.com>
33 * Also see \ref AstCREDITS
35 * \section license License
36 * See http://www.asterisk.org for more information about
37 * the Asterisk project. Please do not directly contact
38 * any of the maintainers of this project for assistance;
39 * the project provides a web site, mailing lists and IRC
40 * channels for your use.
42 * This program is free software, distributed under the terms of
43 * the GNU General Public License Version 2. See the LICENSE file
44 * at the top of the source tree.
46 * \verbinclude LICENSE
51 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
52 of PBX core functions and CLI interface.
63 #include <sys/socket.h>
69 #include <sys/resource.h>
75 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
81 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
83 #include "asterisk/logger.h"
84 #include "asterisk/options.h"
85 #include "asterisk/cli.h"
86 #include "asterisk/channel.h"
87 #include "asterisk/ulaw.h"
88 #include "asterisk/alaw.h"
89 #include "asterisk/callerid.h"
90 #include "asterisk/module.h"
91 #include "asterisk/image.h"
92 #include "asterisk/tdd.h"
93 #include "asterisk/term.h"
94 #include "asterisk/manager.h"
95 #include "asterisk/cdr.h"
96 #include "asterisk/pbx.h"
97 #include "asterisk/enum.h"
98 #include "asterisk/rtp.h"
99 #include "asterisk/app.h"
100 #include "asterisk/lock.h"
101 #include "asterisk/utils.h"
102 #include "asterisk/file.h"
103 #include "asterisk/io.h"
104 #include "asterisk/lock.h"
105 #include "editline/histedit.h"
106 #include "asterisk/config.h"
107 #include "asterisk/version.h"
108 #include "asterisk/linkedlists.h"
109 #include "asterisk/devicestate.h"
111 #include "asterisk/doxyref.h" /* Doxygen documentation */
113 #include "defaults.h"
116 #define AF_LOCAL AF_UNIX
117 #define PF_LOCAL PF_UNIX
120 #define AST_MAX_CONNECTS 128
123 #define WELCOME_MESSAGE ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005 Digium.\n"); \
124 ast_verbose( "Written by Mark Spencer <markster@digium.com>\n"); \
125 ast_verbose( "=========================================================================\n")
127 int option_verbose=0;
129 int option_exec_includes=0;
132 int option_console=0;
133 int option_highpriority=0;
136 int option_initcrypto=0;
138 int option_dumpcore = 0;
139 int option_cache_record_files = 0;
140 int option_timestamp = 0;
141 int option_overrideconfig = 0;
142 int option_reconnect = 0;
143 int option_transcode_slin = 1;
144 int option_transmit_silence_during_record = 0;
145 int option_maxcalls = 0;
146 double option_maxload = 0.0;
147 int option_dontwarn = 0;
148 int option_priority_jumping = 1;
149 int fully_booted = 0;
150 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
151 char debug_filename[AST_FILENAME_MAX] = "";
153 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
154 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
157 int fd; /*!< File descriptor */
158 int p[2]; /*!< Pipe */
159 pthread_t t; /*!< Thread of handler */
162 static struct ast_atexit {
164 struct ast_atexit *next;
167 AST_MUTEX_DEFINE_STATIC(atexitslock);
169 time_t ast_startuptime;
170 time_t ast_lastreloadtime;
172 static History *el_hist = NULL;
173 static EditLine *el = NULL;
174 static char *remotehostname;
176 struct console consoles[AST_MAX_CONNECTS];
178 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
180 static int ast_el_add_history(char *);
181 static int ast_el_read_history(char *);
182 static int ast_el_write_history(char *);
184 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
185 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
186 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
187 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
188 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
189 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
190 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
191 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
192 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
193 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
194 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
195 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
196 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
197 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
198 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
199 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
200 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
202 static char *_argv[256];
203 static int shuttingdown = 0;
204 static int restartnow = 0;
205 static pthread_t consolethread = AST_PTHREADT_NULL;
207 #if !defined(LOW_MEMORY)
208 struct file_version {
209 AST_LIST_ENTRY(file_version) list;
214 static AST_LIST_HEAD_STATIC(file_versions, file_version);
216 void ast_register_file_version(const char *file, const char *version)
218 struct file_version *new;
220 size_t version_length;
222 work = ast_strdupa(version);
223 work = ast_strip(ast_strip_quoted(work, "$", "$"));
224 version_length = strlen(work) + 1;
226 new = calloc(1, sizeof(*new) + version_length);
231 new->version = (char *) new + sizeof(*new);
232 memcpy(new->version, work, version_length);
233 AST_LIST_LOCK(&file_versions);
234 AST_LIST_INSERT_HEAD(&file_versions, new, list);
235 AST_LIST_UNLOCK(&file_versions);
238 void ast_unregister_file_version(const char *file)
240 struct file_version *find;
242 AST_LIST_LOCK(&file_versions);
243 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
244 if (!strcasecmp(find->file, file)) {
245 AST_LIST_REMOVE_CURRENT(&file_versions, list);
249 AST_LIST_TRAVERSE_SAFE_END;
250 AST_LIST_UNLOCK(&file_versions);
255 static char show_version_files_help[] =
256 "Usage: show version files [like <pattern>]\n"
257 " Shows the revision numbers of the files used to build this copy of Asterisk.\n"
258 " Optional regular expression pattern is used to filter the file list.\n";
260 /*! CLI command to list module versions */
261 static int handle_show_version_files(int fd, int argc, char *argv[])
263 #define FORMAT "%-25.25s %-40.40s\n"
264 struct file_version *iterator;
272 if (!strcasecmp(argv[3], "like")) {
273 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
274 return RESULT_SHOWUSAGE;
277 return RESULT_SHOWUSAGE;
285 return RESULT_SHOWUSAGE;
288 ast_cli(fd, FORMAT, "File", "Revision");
289 ast_cli(fd, FORMAT, "----", "--------");
290 AST_LIST_LOCK(&file_versions);
291 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
292 if (havename && strcasecmp(iterator->file, argv[3]))
295 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
298 ast_cli(fd, FORMAT, iterator->file, iterator->version);
303 AST_LIST_UNLOCK(&file_versions);
305 ast_cli(fd, "%d files listed.\n", count_files);
311 return RESULT_SUCCESS;
315 static char *complete_show_version_files(char *line, char *word, int pos, int state)
317 struct file_version *find;
320 int matchlen = strlen(word);
325 AST_LIST_LOCK(&file_versions);
326 AST_LIST_TRAVERSE(&file_versions, find, list) {
327 if (!strncasecmp(word, find->file, matchlen)) {
328 if (++which > state) {
329 ret = strdup(find->file);
334 AST_LIST_UNLOCK(&file_versions);
338 #endif /* ! LOW_MEMORY */
340 int ast_register_atexit(void (*func)(void))
343 struct ast_atexit *ae;
344 ast_unregister_atexit(func);
345 ae = malloc(sizeof(struct ast_atexit));
346 ast_mutex_lock(&atexitslock);
348 memset(ae, 0, sizeof(struct ast_atexit));
354 ast_mutex_unlock(&atexitslock);
358 void ast_unregister_atexit(void (*func)(void))
360 struct ast_atexit *ae, *prev = NULL;
361 ast_mutex_lock(&atexitslock);
364 if (ae->func == func) {
366 prev->next = ae->next;
374 ast_mutex_unlock(&atexitslock);
377 static int fdprint(int fd, const char *s)
379 return write(fd, s, strlen(s) + 1);
382 /*! NULL handler so we can collect the child exit status */
383 static void null_sig_handler(int signal)
388 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
389 static unsigned int safe_system_level = 0;
390 static void *safe_system_prev_handler;
392 int ast_safe_system(const char *s)
397 struct rusage rusage;
401 /* keep track of how many ast_safe_system() functions
402 are running at this moment
404 ast_mutex_lock(&safe_system_lock);
405 level = safe_system_level++;
407 /* only replace the handler if it has not already been done */
409 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
411 ast_mutex_unlock(&safe_system_lock);
416 /* Close file descriptors and launch system command */
417 for (x = STDERR_FILENO + 1; x < 4096; x++)
419 execl("/bin/sh", "/bin/sh", "-c", s, NULL);
421 } else if (pid > 0) {
423 res = wait4(pid, &status, 0, &rusage);
425 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
427 } else if (errno != EINTR)
431 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
435 ast_mutex_lock(&safe_system_lock);
436 level = --safe_system_level;
438 /* only restore the handler if we are the last one */
440 signal(SIGCHLD, safe_system_prev_handler);
442 ast_mutex_unlock(&safe_system_lock);
448 * write the string to all attached console clients
450 static void ast_network_puts(const char *string)
453 for (x=0;x<AST_MAX_CONNECTS; x++) {
454 if (consoles[x].fd > -1)
455 fdprint(consoles[x].p[1], string);
460 * write the string to the console, and all attached
463 void ast_console_puts(const char *string)
465 fputs(string, stdout);
467 ast_network_puts(string);
470 static void network_verboser(const char *s, int pos, int replace, int complete)
474 char *t = alloca(strlen(s) + 2);
476 sprintf(t, "\r%s", s);
480 ast_log(LOG_ERROR, "Out of memory\n");
489 static pthread_t lthread;
491 static void *netconsole(void *vconsole)
493 struct console *con = vconsole;
494 char hostname[MAXHOSTNAMELEN]="";
497 struct pollfd fds[2];
499 if (gethostname(hostname, sizeof(hostname)-1))
500 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
501 snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
502 fdprint(con->fd, tmp);
505 fds[0].events = POLLIN;
507 fds[1].fd = con->p[0];
508 fds[1].events = POLLIN;
511 res = poll(fds, 2, -1);
514 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
517 if (fds[0].revents) {
518 res = read(con->fd, tmp, sizeof(tmp));
523 ast_cli_command(con->fd, tmp);
525 if (fds[1].revents) {
526 res = read(con->p[0], tmp, sizeof(tmp));
528 ast_log(LOG_ERROR, "read returned %d\n", res);
531 res = write(con->fd, tmp, res);
536 if (option_verbose > 2)
537 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
546 static void *listener(void *unused)
548 struct sockaddr_un sunaddr;
553 struct pollfd fds[1];
555 pthread_attr_init(&attr);
556 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
560 fds[0].fd = ast_socket;
561 fds[0].events= POLLIN;
562 s = poll(fds, 1, -1);
565 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
568 len = sizeof(sunaddr);
569 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
572 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
574 for (x=0;x<AST_MAX_CONNECTS;x++) {
575 if (consoles[x].fd < 0) {
576 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
577 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
579 fdprint(s, "Server failed to create pipe\n");
583 flags = fcntl(consoles[x].p[1], F_GETFL);
584 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
586 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
587 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
589 fdprint(s, "Server failed to spawn thread\n");
595 if (x >= AST_MAX_CONNECTS) {
596 fdprint(s, "No more connections allowed\n");
597 ast_log(LOG_WARNING, "No more connections allowed\n");
599 } else if (consoles[x].fd > -1) {
600 if (option_verbose > 2)
601 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
608 static int ast_makesocket(void)
610 struct sockaddr_un sunaddr;
616 for (x = 0; x < AST_MAX_CONNECTS; x++)
618 unlink(ast_config_AST_SOCKET);
619 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
620 if (ast_socket < 0) {
621 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
624 memset(&sunaddr, 0, sizeof(sunaddr));
625 sunaddr.sun_family = AF_LOCAL;
626 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
627 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
629 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
634 res = listen(ast_socket, 2);
636 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
641 ast_register_verbose(network_verboser);
642 ast_pthread_create(<hread, NULL, listener, NULL);
644 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
646 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
647 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
653 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
655 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
656 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
662 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
663 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
665 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
667 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", (int *) &p);
668 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
669 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
675 static int ast_tryconnect(void)
677 struct sockaddr_un sunaddr;
679 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
680 if (ast_consock < 0) {
681 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
684 memset(&sunaddr, 0, sizeof(sunaddr));
685 sunaddr.sun_family = AF_LOCAL;
686 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
687 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
697 Called by soft_hangup to interrupt the poll, read, or other
698 system call. We don't actually need to do anything though.
699 Remember: Cannot EVER ast_log from within a signal handler
700 SLD: seems to be some pthread activity relating to the printf anyway:
701 which is leading to a deadlock?
703 static void urg_handler(int num)
706 if (option_debug > 2)
707 printf("-- Asterisk Urgent handler\n");
709 signal(num, urg_handler);
713 static void hup_handler(int num)
715 if (option_verbose > 1)
716 printf("Received HUP signal -- Reloading configs\n");
718 execvp(_argv[0], _argv);
719 /* XXX This could deadlock XXX */
720 ast_module_reload(NULL);
721 signal(num, hup_handler);
724 static void child_handler(int sig)
726 /* Must not ever ast_log or ast_verbose within signal handler */
730 * Reap all dead children -- not just one
732 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
734 if (n == 0 && option_debug)
735 printf("Huh? Child handler, but nobody there?\n");
736 signal(sig, child_handler);
739 /*! Set an X-term or screen title */
740 static void set_title(char *text)
742 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
743 fprintf(stdout, "\033]2;%s\007", text);
746 static void set_icon(char *text)
748 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
749 fprintf(stdout, "\033]1;%s\007", text);
752 /*! We set ourselves to a high priority, that we might pre-empt everything
753 else. If your PBX has heavy activity on it, this is a good thing. */
754 int ast_set_priority(int pri)
756 struct sched_param sched;
757 memset(&sched, 0, sizeof(sched));
760 sched.sched_priority = 10;
761 if (sched_setscheduler(0, SCHED_RR, &sched)) {
762 ast_log(LOG_WARNING, "Unable to set high priority\n");
766 ast_verbose("Set to realtime thread\n");
768 sched.sched_priority = 0;
769 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
770 ast_log(LOG_WARNING, "Unable to set normal priority\n");
776 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
777 ast_log(LOG_WARNING, "Unable to set high priority\n");
781 ast_verbose("Set to high priority\n");
783 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
784 ast_log(LOG_WARNING, "Unable to set normal priority\n");
792 static void ast_run_atexits(void)
794 struct ast_atexit *ae;
795 ast_mutex_lock(&atexitslock);
802 ast_mutex_unlock(&atexitslock);
805 static void quit_handler(int num, int nice, int safeshutdown, int restart)
807 char filename[80] = "";
810 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
811 ast_cdr_engine_term();
815 /* Begin shutdown routine, hanging up active channels */
816 ast_begin_shutdown(1);
817 if (option_verbose && option_console)
818 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
822 /* Wait up to 15 seconds for all channels to go away */
825 if (!ast_active_channels())
829 /* Sleep 1/10 of a second */
834 ast_begin_shutdown(0);
835 if (option_verbose && option_console)
836 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
838 if (!ast_active_channels())
847 if (option_verbose && option_console)
848 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
852 if (option_console || option_remote) {
854 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
855 if (!ast_strlen_zero(filename))
856 ast_el_write_history(filename);
860 history_end(el_hist);
863 ast_verbose("Executing last minute cleanups\n");
866 if (option_verbose && option_console)
867 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
868 else if (option_debug)
869 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
870 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
871 if (ast_socket > -1) {
875 if (ast_consock > -1)
878 unlink((char *)ast_config_AST_SOCKET);
879 if (!option_remote) unlink((char *)ast_config_AST_PID);
882 if (option_verbose || option_console)
883 ast_verbose("Preparing for Asterisk restart...\n");
884 /* Mark all FD's for closing on exec */
885 for (x=3;x<32768;x++) {
886 fcntl(x, F_SETFD, FD_CLOEXEC);
888 if (option_verbose || option_console)
889 ast_verbose("Restarting Asterisk NOW...\n");
895 /* If there is a consolethread running send it a SIGHUP
896 so it can execvp, otherwise we can do it ourselves */
897 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
898 pthread_kill(consolethread, SIGHUP);
899 /* Give the signal handler some time to complete */
902 execvp(_argv[0], _argv);
911 static void __quit_handler(int num)
913 quit_handler(num, 0, 1, 0);
916 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
919 if (!strncmp(s, cmp, strlen(cmp))) {
921 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
927 static void console_verboser(const char *s, int pos, int replace, int complete)
931 /* Return to the beginning of the line */
933 fprintf(stdout, "\r");
934 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
935 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
936 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
937 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
941 fputs(c + pos,stdout);
943 fputs(s + pos,stdout);
946 /* Wake up a poll()ing console */
947 if (option_console && consolethread != AST_PTHREADT_NULL)
948 pthread_kill(consolethread, SIGURG);
952 static int ast_all_zeros(char *s)
962 static void consolehandler(char *s)
966 /* Called when readline data is available */
967 if (s && !ast_all_zeros(s))
968 ast_el_add_history(s);
969 /* Give the console access to the shell */
971 /* The real handler for bang */
974 ast_safe_system(s+1);
976 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
978 ast_cli_command(STDOUT_FILENO, s);
980 fprintf(stdout, "\nUse \"quit\" to exit\n");
983 static int remoteconsolehandler(char *s)
986 /* Called when readline data is available */
987 if (s && !ast_all_zeros(s))
988 ast_el_add_history(s);
989 /* Give the console access to the shell */
991 /* The real handler for bang */
994 ast_safe_system(s+1);
996 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
999 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1000 (s[4] == '\0' || isspace(s[4]))) {
1001 quit_handler(0, 0, 0, 0);
1005 fprintf(stdout, "\nUse \"quit\" to exit\n");
1010 static char abort_halt_help[] =
1011 "Usage: abort shutdown\n"
1012 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1013 " call operations.\n";
1015 static char shutdown_now_help[] =
1017 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1019 static char shutdown_gracefully_help[] =
1020 "Usage: stop gracefully\n"
1021 " Causes Asterisk to not accept new calls, and exit when all\n"
1022 " active calls have terminated normally.\n";
1024 static char shutdown_when_convenient_help[] =
1025 "Usage: stop when convenient\n"
1026 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1028 static char restart_now_help[] =
1029 "Usage: restart now\n"
1030 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1033 static char restart_gracefully_help[] =
1034 "Usage: restart gracefully\n"
1035 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1036 " restart when all active calls have ended.\n";
1038 static char restart_when_convenient_help[] =
1039 "Usage: restart when convenient\n"
1040 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1042 static char bang_help[] =
1043 "Usage: !<command>\n"
1044 " Executes a given shell command\n";
1047 static int handle_quit(int fd, int argc, char *argv[])
1050 return RESULT_SHOWUSAGE;
1051 quit_handler(0, 0, 1, 0);
1052 return RESULT_SUCCESS;
1056 static int handle_shutdown_now(int fd, int argc, char *argv[])
1059 return RESULT_SHOWUSAGE;
1060 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1061 return RESULT_SUCCESS;
1064 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1067 return RESULT_SHOWUSAGE;
1068 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1069 return RESULT_SUCCESS;
1072 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1075 return RESULT_SHOWUSAGE;
1076 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1077 return RESULT_SUCCESS;
1080 static int handle_restart_now(int fd, int argc, char *argv[])
1083 return RESULT_SHOWUSAGE;
1084 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1085 return RESULT_SUCCESS;
1088 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1091 return RESULT_SHOWUSAGE;
1092 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1093 return RESULT_SUCCESS;
1096 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1099 return RESULT_SHOWUSAGE;
1100 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1101 return RESULT_SUCCESS;
1104 static int handle_abort_halt(int fd, int argc, char *argv[])
1107 return RESULT_SHOWUSAGE;
1108 ast_cancel_shutdown();
1110 return RESULT_SUCCESS;
1113 static int handle_bang(int fd, int argc, char *argv[])
1115 return RESULT_SUCCESS;
1118 #define ASTERISK_PROMPT "*CLI> "
1120 #define ASTERISK_PROMPT2 "%s*CLI> "
1122 static struct ast_cli_entry core_cli[] = {
1123 { { "abort", "halt", NULL }, handle_abort_halt,
1124 "Cancel a running halt", abort_halt_help },
1125 { { "stop", "now", NULL }, handle_shutdown_now,
1126 "Shut down Asterisk immediately", shutdown_now_help },
1127 { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1128 "Gracefully shut down Asterisk", shutdown_gracefully_help },
1129 { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1130 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1131 { { "restart", "now", NULL }, handle_restart_now,
1132 "Restart Asterisk immediately", restart_now_help },
1133 { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1134 "Restart Asterisk gracefully", restart_gracefully_help },
1135 { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1136 "Restart Asterisk at empty call volume", restart_when_convenient_help },
1137 { { "!", NULL }, handle_bang,
1138 "Execute a shell command", bang_help },
1139 #if !defined(LOW_MEMORY)
1140 { { "show", "version", "files", NULL }, handle_show_version_files,
1141 "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1142 #endif /* ! LOW_MEMORY */
1145 static int ast_el_read_char(EditLine *el, char *cp)
1149 struct pollfd fds[2];
1156 fds[0].fd = ast_consock;
1157 fds[0].events = POLLIN;
1159 fds[1].fd = STDIN_FILENO;
1160 fds[1].events = POLLIN;
1163 res = poll(fds, max, -1);
1167 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1171 if (!option_exec && fds[1].revents) {
1172 num_read = read(STDIN_FILENO, cp, 1);
1178 if (fds[0].revents) {
1179 res = read(ast_consock, buf, sizeof(buf) - 1);
1180 /* if the remote side disappears exit */
1182 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1183 if (!option_reconnect) {
1184 quit_handler(0, 0, 0, 0);
1187 int reconnects_per_second = 20;
1188 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1189 for (tries=0;tries<30 * reconnects_per_second;tries++) {
1190 if (ast_tryconnect()) {
1191 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1192 printf(term_quit());
1196 usleep(1000000 / reconnects_per_second);
1199 if (tries >= 30 * reconnects_per_second) {
1200 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1201 quit_handler(0, 0, 0, 0);
1208 if (!option_exec && !lastpos)
1209 write(STDOUT_FILENO, "\r", 1);
1210 write(STDOUT_FILENO, buf, res);
1211 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1224 static char *cli_prompt(EditLine *el)
1226 static char prompt[200];
1231 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1232 char *t = pfmt, *p = prompt;
1233 memset(prompt, 0, sizeof(prompt));
1234 while (*t != '\0' && *p < sizeof(prompt)) {
1236 char hostname[MAXHOSTNAMELEN]="";
1243 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1247 case 'C': /* color */
1249 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1250 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1252 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1253 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1257 /* If the color has been reset correctly, then there's no need to reset it later */
1258 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1264 case 'd': /* date */
1265 memset(&tm, 0, sizeof(struct tm));
1267 if (localtime_r(&(tv.tv_sec), &tm)) {
1268 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1271 case 'h': /* hostname */
1272 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1273 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1275 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1278 case 'H': /* short hostname */
1279 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1280 for (i=0;i<sizeof(hostname);i++) {
1281 if (hostname[i] == '.') {
1286 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1288 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1292 case 'l': /* load avg */
1294 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1295 float avg1, avg2, avg3;
1296 int actproc, totproc, npid, which;
1297 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1298 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1299 if (sscanf(t, "%d", &which) == 1) {
1302 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1305 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1308 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1311 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1314 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1321 case 't': /* time */
1322 memset(&tm, 0, sizeof(struct tm));
1324 if (localtime_r(&(tv.tv_sec), &tm)) {
1325 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1328 case '#': /* process console or remote? */
1329 if (! option_remote) {
1330 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1332 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1335 case '%': /* literal % */
1336 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1338 case '\0': /* % is last character - prevent bug */
1342 while (*p != '\0') {
1353 /* Force colors back to normal at end */
1354 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1355 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1356 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1358 strncat(p, term_code, sizeof(term_code));
1361 } else if (remotehostname)
1362 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1364 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1369 static char **ast_el_strtoarr(char *buf)
1371 char **match_list = NULL, *retstr;
1372 size_t match_list_len;
1376 while ( (retstr = strsep(&buf, " ")) != NULL) {
1378 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1380 if (matches + 1 >= match_list_len) {
1381 match_list_len <<= 1;
1382 match_list = realloc(match_list, match_list_len * sizeof(char *));
1385 match_list[matches++] = strdup(retstr);
1389 return (char **) NULL;
1391 if (matches>= match_list_len)
1392 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
1394 match_list[matches] = (char *) NULL;
1399 static int ast_el_sort_compare(const void *i1, const void *i2)
1403 s1 = ((char **)i1)[0];
1404 s2 = ((char **)i2)[0];
1406 return strcasecmp(s1, s2);
1409 static int ast_cli_display_match_list(char **matches, int len, int max)
1411 int i, idx, limit, count;
1412 int screenwidth = 0;
1413 int numoutput = 0, numoutputline = 0;
1415 screenwidth = ast_get_termcols(STDOUT_FILENO);
1417 /* find out how many entries can be put on one line, with two spaces between strings */
1418 limit = screenwidth / (max + 2);
1422 /* how many lines of output */
1423 count = len / limit;
1424 if (count * limit < len)
1429 qsort(&matches[0], (size_t)(len + 1), sizeof(char *), ast_el_sort_compare);
1431 for (; count > 0; count--) {
1433 for (i=0; i < limit && matches[idx]; i++, idx++) {
1435 /* Don't print dupes */
1436 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1439 matches[idx] = NULL;
1445 fprintf(stdout, "%-*s ", max, matches[idx]);
1447 matches[idx] = NULL;
1449 if (numoutputline > 0)
1450 fprintf(stdout, "\n");
1457 static char *cli_complete(EditLine *el, int ch)
1463 int retval = CC_ERROR;
1467 LineInfo *lf = (LineInfo *)el_line(el);
1469 *(char *)lf->cursor = '\0';
1470 ptr = (char *)lf->cursor;
1472 while (ptr > lf->buffer) {
1473 if (isspace(*ptr)) {
1481 len = lf->cursor - ptr;
1483 if (option_remote) {
1484 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1485 fdprint(ast_consock, buf);
1486 res = read(ast_consock, buf, sizeof(buf));
1488 nummatches = atoi(buf);
1490 if (nummatches > 0) {
1492 int mlen = 0, maxmbuf = 2048;
1493 /* Start with a 2048 byte buffer */
1494 mbuf = malloc(maxmbuf);
1496 return (char *)(CC_ERROR);
1497 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1498 fdprint(ast_consock, buf);
1501 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1502 if (mlen + 1024 > maxmbuf) {
1503 /* Every step increment buffer 1024 bytes */
1505 mbuf = realloc(mbuf, maxmbuf);
1507 return (char *)(CC_ERROR);
1509 /* Only read 1024 bytes at a time */
1510 res = read(ast_consock, mbuf + mlen, 1024);
1516 matches = ast_el_strtoarr(mbuf);
1519 matches = (char **) NULL;
1524 nummatches = ast_cli_generatornummatches((char *)lf->buffer,ptr);
1525 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1530 int matches_num, maxlen, match_len;
1532 if (matches[0][0] != '\0') {
1533 el_deletestr(el, (int) len);
1534 el_insertstr(el, matches[0]);
1535 retval = CC_REFRESH;
1538 if (nummatches == 1) {
1539 /* Found an exact match */
1540 el_insertstr(el, " ");
1541 retval = CC_REFRESH;
1543 /* Must be more than one match */
1544 for (i=1, maxlen=0; matches[i]; i++) {
1545 match_len = strlen(matches[i]);
1546 if (match_len > maxlen)
1549 matches_num = i - 1;
1550 if (matches_num >1) {
1551 fprintf(stdout, "\n");
1552 ast_cli_display_match_list(matches, nummatches, maxlen);
1553 retval = CC_REDISPLAY;
1555 el_insertstr(el," ");
1556 retval = CC_REFRESH;
1562 return (char *)(long)retval;
1565 static int ast_el_initialize(void)
1568 char *editor = getenv("AST_EDITOR");
1572 if (el_hist != NULL)
1573 history_end(el_hist);
1575 el = el_init("asterisk", stdin, stdout, stderr);
1576 el_set(el, EL_PROMPT, cli_prompt);
1578 el_set(el, EL_EDITMODE, 1);
1579 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1580 el_hist = history_init();
1581 if (!el || !el_hist)
1584 /* setup history with 100 entries */
1585 history(el_hist, &ev, H_SETSIZE, 100);
1587 el_set(el, EL_HIST, history, el_hist);
1589 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1590 /* Bind <tab> to command completion */
1591 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1592 /* Bind ? to command completion */
1593 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1594 /* Bind ^D to redisplay */
1595 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1600 static int ast_el_add_history(char *buf)
1604 if (el_hist == NULL || el == NULL)
1605 ast_el_initialize();
1606 if (strlen(buf) > 256)
1608 return (history(el_hist, &ev, H_ENTER, buf));
1611 static int ast_el_write_history(char *filename)
1615 if (el_hist == NULL || el == NULL)
1616 ast_el_initialize();
1618 return (history(el_hist, &ev, H_SAVE, filename));
1621 static int ast_el_read_history(char *filename)
1627 if (el_hist == NULL || el == NULL)
1628 ast_el_initialize();
1630 if ((f = fopen(filename, "r")) == NULL)
1634 fgets(buf, sizeof(buf), f);
1635 if (!strcmp(buf, "_HiStOrY_V2_\n"))
1637 if (ast_all_zeros(buf))
1639 if ((ret = ast_el_add_history(buf)) == -1)
1647 static void ast_remotecontrol(char * data)
1651 char filename[80] = "";
1662 read(ast_consock, buf, sizeof(buf));
1664 write(ast_consock, data, strlen(data) + 1);
1666 hostname = strsep(&stringp, "/");
1667 cpid = strsep(&stringp, "/");
1668 version = strsep(&stringp, "\n");
1670 version = "<Version Unknown>";
1672 strsep(&stringp, ".");
1677 snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1678 fdprint(ast_consock, tmp);
1679 snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
1680 fdprint(ast_consock, tmp);
1681 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1682 remotehostname = hostname;
1684 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1685 if (el_hist == NULL || el == NULL)
1686 ast_el_initialize();
1688 el_set(el, EL_GETCFN, ast_el_read_char);
1690 if (!ast_strlen_zero(filename))
1691 ast_el_read_history(filename);
1693 if (option_exec && data) { /* hack to print output then exit if asterisk -rx is used */
1695 struct pollfd fds[0];
1696 fds[0].fd = ast_consock;
1697 fds[0].events = POLLIN;
1699 while(poll(fds, 1, 100) > 0) {
1700 ast_el_read_char(el, &tempchar);
1705 ebuf = (char *)el_gets(el, &num);
1707 if (!ast_strlen_zero(ebuf)) {
1708 if (ebuf[strlen(ebuf)-1] == '\n')
1709 ebuf[strlen(ebuf)-1] = '\0';
1710 if (!remoteconsolehandler(ebuf)) {
1711 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1713 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1719 printf("\nDisconnected from Asterisk server\n");
1722 static int show_version(void)
1724 printf("Asterisk " ASTERISK_VERSION "\n");
1728 static int show_cli_help(void) {
1729 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 2000 - 2005, Digium.\n");
1730 printf("Usage: asterisk [OPTIONS]\n");
1731 printf("Valid Options:\n");
1732 printf(" -V Display version number and exit\n");
1733 printf(" -C <configfile> Use an alternate configuration file\n");
1734 printf(" -G <group> Run as a group other than the caller\n");
1735 printf(" -U <user> Run as a user other than the caller\n");
1736 printf(" -c Provide console CLI\n");
1737 printf(" -d Enable extra debugging\n");
1738 printf(" -f Do not fork\n");
1739 printf(" -g Dump core in case of a crash\n");
1740 printf(" -h This help screen\n");
1741 printf(" -i Initialize crypto keys at startup\n");
1742 printf(" -n Disable console colorization\n");
1743 printf(" -p Run as pseudo-realtime thread\n");
1744 printf(" -q Quiet mode (suppress output)\n");
1745 printf(" -r Connect to Asterisk on this machine\n");
1746 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
1747 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
1748 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
1749 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
1750 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
1755 static void ast_readconfig(void) {
1756 struct ast_config *cfg;
1757 struct ast_variable *v;
1758 char *config = AST_CONFIG_FILE;
1760 if (option_overrideconfig == 1) {
1761 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
1763 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
1765 cfg = ast_config_load(config);
1768 /* init with buildtime config */
1769 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
1770 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
1771 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_VAR_DIR));
1772 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
1773 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
1774 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
1775 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
1776 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
1777 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
1778 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
1779 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
1780 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
1782 /* no asterisk.conf? no problem, use buildtime config! */
1786 v = ast_variable_browse(cfg, "files");
1788 if (!strcasecmp(v->name, "astctlpermissions")) {
1789 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
1790 } else if (!strcasecmp(v->name, "astctlowner")) {
1791 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
1792 } else if (!strcasecmp(v->name, "astctlgroup")) {
1793 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
1794 } else if (!strcasecmp(v->name, "astctl")) {
1795 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
1799 v = ast_variable_browse(cfg, "directories");
1801 if (!strcasecmp(v->name, "astetcdir")) {
1802 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
1803 } else if (!strcasecmp(v->name, "astspooldir")) {
1804 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
1805 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
1806 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1807 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
1808 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/%s", v->value, "astdb");
1809 } else if (!strcasecmp(v->name, "astlogdir")) {
1810 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
1811 } else if (!strcasecmp(v->name, "astagidir")) {
1812 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
1813 } else if (!strcasecmp(v->name, "astrundir")) {
1814 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
1815 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
1816 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
1817 } else if (!strcasecmp(v->name, "astmoddir")) {
1818 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
1822 v = ast_variable_browse(cfg, "options");
1824 /* verbose level (-v at startup) */
1825 if (!strcasecmp(v->name, "verbose")) {
1826 option_verbose = atoi(v->value);
1827 /* whether or not to force timestamping. (-T at startup) */
1828 } else if (!strcasecmp(v->name, "timestamp")) {
1829 option_timestamp = ast_true(v->value);
1830 /* whether or not to support #exec in config files */
1831 } else if (!strcasecmp(v->name, "execincludes")) {
1832 option_exec_includes = ast_true(v->value);
1833 /* debug level (-d at startup) */
1834 } else if (!strcasecmp(v->name, "debug")) {
1836 if (sscanf(v->value, "%d", &option_debug) != 1) {
1837 option_debug = ast_true(v->value);
1839 /* Disable forking (-f at startup) */
1840 } else if (!strcasecmp(v->name, "nofork")) {
1841 option_nofork = ast_true(v->value);
1842 /* Run quietly (-q at startup ) */
1843 } else if (!strcasecmp(v->name, "quiet")) {
1844 option_quiet = ast_true(v->value);
1845 /* Run as console (-c at startup, implies nofork) */
1846 } else if (!strcasecmp(v->name, "console")) {
1847 option_console = ast_true(v->value);
1848 /* Run with highg priority if the O/S permits (-p at startup) */
1849 } else if (!strcasecmp(v->name, "highpriority")) {
1850 option_highpriority = ast_true(v->value);
1851 /* Initialize RSA auth keys (IAX2) (-i at startup) */
1852 } else if (!strcasecmp(v->name, "initcrypto")) {
1853 option_initcrypto = ast_true(v->value);
1854 /* Disable ANSI colors for console (-c at startup) */
1855 } else if (!strcasecmp(v->name, "nocolor")) {
1856 option_nocolor = ast_true(v->value);
1857 /* Disable some usage warnings for picky people :p */
1858 } else if (!strcasecmp(v->name, "dontwarn")) {
1859 option_dontwarn = ast_true(v->value);
1860 /* Dump core in case of crash (-g) */
1861 } else if (!strcasecmp(v->name, "dumpcore")) {
1862 option_dumpcore = ast_true(v->value);
1863 /* Cache recorded sound files to another directory during recording */
1864 } else if (!strcasecmp(v->name, "cache_record_files")) {
1865 option_cache_record_files = ast_true(v->value);
1866 /* Specify cache directory */
1867 } else if (!strcasecmp(v->name, "record_cache_dir")) {
1868 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
1869 /* Build transcode paths via SLINEAR, instead of directly */
1870 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
1871 option_transcode_slin = ast_true(v->value);
1872 /* Transmit SLINEAR silence while a channel is being recorded */
1873 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
1874 option_transmit_silence_during_record = ast_true(v->value);
1875 } else if (!strcasecmp(v->name, "maxcalls")) {
1876 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
1877 option_maxcalls = 0;
1879 } else if (!strcasecmp(v->name, "maxload")) {
1882 if (getloadavg(test, 1) == -1) {
1883 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
1884 option_maxload = 0.0;
1885 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
1886 option_maxload = 0.0;
1891 ast_config_destroy(cfg);
1894 int main(int argc, char *argv[])
1897 char filename[80] = "";
1898 char hostname[MAXHOSTNAMELEN]="";
1905 int is_child_of_nonroot=0;
1907 char *runuser=NULL, *rungroup=NULL;
1909 /* Remember original args for restart */
1910 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
1911 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
1912 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
1914 for (x=0;x<argc;x++)
1918 /* if the progname is rasterisk consider it a remote console */
1919 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
1923 if (gethostname(hostname, sizeof(hostname)-1))
1924 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1925 ast_mainpid = getpid();
1931 /* When Asterisk restarts after it has dropped the root privileges,
1932 * it can't issue setuid(), setgid(), setgroups() or set_priority()
1934 if (getenv("ASTERISK_ALREADY_NONROOT"))
1935 is_child_of_nonroot=1;
1937 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1938 /* Check if we're root */
1941 ast_log(LOG_ERROR, "Must be run as root\n");
1945 /* Check for options */
1946 while((c=getopt(argc, argv, "tThfdvVqprRgcinx:U:G:C:L:M:")) != -1) {
1972 option_highpriority++;
1979 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
1980 option_maxcalls = 0;
1983 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
1984 option_maxload = 0.0;
1990 option_cache_record_files++;
2000 ast_copy_string((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE));
2001 option_overrideconfig++;
2004 option_initcrypto++;
2026 /* For remote connections, change the name of the remote connection.
2027 * We do this for the benefit of init scripts (which need to know if/when
2028 * the main asterisk process has died yet). */
2029 if (option_remote) {
2030 strcpy(argv[0], "rasterisk");
2031 for (x = 1; x < argc; x++) {
2032 argv[x] = argv[0] + 10;
2036 if (option_dumpcore) {
2038 memset(&l, 0, sizeof(l));
2039 l.rlim_cur = RLIM_INFINITY;
2040 l.rlim_max = RLIM_INFINITY;
2041 if (setrlimit(RLIMIT_CORE, &l)) {
2042 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2046 if (option_console && !option_verbose)
2047 ast_verbose("[ Reading Master Configuration ]");
2052 if (!is_child_of_nonroot && ast_set_priority(option_highpriority)) {
2056 if (!is_child_of_nonroot && rungroup) {
2058 gr = getgrnam(rungroup);
2060 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2063 if (setgid(gr->gr_gid)) {
2064 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", gr->gr_gid, rungroup);
2068 ast_verbose("Running as group '%s'\n", rungroup);
2071 if (!is_child_of_nonroot && runuser) {
2073 pw = getpwnam(runuser);
2075 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2078 if (setuid(pw->pw_uid)) {
2079 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", pw->pw_uid, runuser);
2082 setenv("ASTERISK_ALREADY_NONROOT","yes",1);
2084 ast_verbose("Running as user '%s'\n", runuser);
2087 #endif /* __CYGWIN__ */
2093 if (option_console && !option_verbose)
2094 ast_verbose("[ Initializing Custom Configuration Options ]");
2095 /* custom config setup */
2096 register_config_cli();
2100 if (option_console) {
2101 if (el_hist == NULL || el == NULL)
2102 ast_el_initialize();
2104 if (!ast_strlen_zero(filename))
2105 ast_el_read_history(filename);
2108 if (ast_tryconnect()) {
2109 /* One is already running */
2110 if (option_remote) {
2112 ast_remotecontrol(xarg);
2113 quit_handler(0, 0, 0, 0);
2116 printf(term_quit());
2117 ast_register_verbose(console_verboser);
2119 ast_remotecontrol(NULL);
2120 quit_handler(0, 0, 0, 0);
2123 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
2124 printf(term_quit());
2127 } else if (option_remote || option_exec) {
2128 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n",ast_config_AST_SOCKET);
2129 printf(term_quit());
2132 /* Blindly write pid file since we couldn't connect */
2133 unlink((char *)ast_config_AST_PID);
2134 f = fopen((char *)ast_config_AST_PID, "w");
2136 fprintf(f, "%d\n", getpid());
2139 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
2141 if (!option_verbose && !option_debug && !option_nofork && !option_console) {
2143 /* Blindly re-write pid file since we are forking */
2144 unlink((char *)ast_config_AST_PID);
2145 f = fopen((char *)ast_config_AST_PID, "w");
2147 fprintf(f, "%d\n", getpid());
2150 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
2153 /* Test recursive mutex locking. */
2154 if (test_for_thread_safety())
2155 ast_verbose("Warning! Asterisk is not thread safe.\n");
2159 sigaddset(&sigs, SIGHUP);
2160 sigaddset(&sigs, SIGTERM);
2161 sigaddset(&sigs, SIGINT);
2162 sigaddset(&sigs, SIGPIPE);
2163 sigaddset(&sigs, SIGWINCH);
2164 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2165 if (option_console || option_verbose || option_remote)
2166 ast_register_verbose(console_verboser);
2167 /* Print a welcome message if desired */
2168 if (option_verbose || option_console) {
2171 if (option_console && !option_verbose)
2172 ast_verbose("[ Booting...");
2174 signal(SIGURG, urg_handler);
2175 signal(SIGINT, __quit_handler);
2176 signal(SIGTERM, __quit_handler);
2177 signal(SIGHUP, hup_handler);
2178 signal(SIGCHLD, child_handler);
2179 signal(SIGPIPE, SIG_IGN);
2181 /* ensure that the random number generators are seeded with a different value every time
2184 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2185 srandom((unsigned int) getpid() + (unsigned int) time(NULL));
2187 if (init_logger()) {
2188 printf(term_quit());
2191 if (dnsmgr_init()) {
2192 printf(term_quit());
2195 /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2196 if (load_modules(1)) {
2197 printf(term_quit());
2200 ast_channels_init();
2201 if (init_manager()) {
2202 printf(term_quit());
2205 if (ast_cdr_engine_init()) {
2206 printf(term_quit());
2209 if (ast_device_state_engine_init()) {
2210 printf(term_quit());
2214 if (ast_image_init()) {
2215 printf(term_quit());
2218 if (ast_file_init()) {
2219 printf(term_quit());
2223 printf(term_quit());
2226 if (load_modules(0)) {
2227 printf(term_quit());
2230 if (init_framer()) {
2231 printf(term_quit());
2235 printf(term_quit());
2238 if (ast_enum_init()) {
2239 printf(term_quit());
2243 /* This should no longer be necessary */
2244 /* sync cust config and reload some internals in case a custom config handler binded to them */
2245 read_ast_cust_config();
2253 /* We might have the option of showing a console, but for now just
2255 if (option_console && !option_verbose)
2256 ast_verbose(" ]\n");
2257 if (option_verbose || option_console)
2258 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2260 consolethread = pthread_self();
2262 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2263 #ifdef __AST_DEBUG_MALLOC
2266 time(&ast_startuptime);
2267 ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2268 if (option_console) {
2269 /* Console stuff now... */
2270 /* Register our quit function */
2272 set_icon("Asterisk");
2273 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
2277 buf = (char *)el_gets(el, &num);
2279 if (buf[strlen(buf)-1] == '\n')
2280 buf[strlen(buf)-1] = '\0';
2282 consolehandler((char *)buf);
2284 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2285 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2286 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2288 fd = open("/dev/null", O_RDWR);
2290 dup2(fd, STDOUT_FILENO);
2291 dup2(fd, STDIN_FILENO);
2293 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2301 for(;;) { /* apparently needed for the MACos */
2302 struct pollfd p = { -1 /* no descriptor */, 0, 0 };