2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, 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 - 2006, 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.
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
71 #include <sys/socket.h>
77 #include <sys/resource.h>
82 #include <sys/prctl.h>
87 #include <sys/prctl.h>
90 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
93 int daemon(int, int); /* defined in libresolv of all places */
97 #include "asterisk/logger.h"
98 #include "asterisk/options.h"
99 #include "asterisk/cli.h"
100 #include "asterisk/channel.h"
101 #include "asterisk/ulaw.h"
102 #include "asterisk/alaw.h"
103 #include "asterisk/callerid.h"
104 #include "asterisk/image.h"
105 #include "asterisk/tdd.h"
106 #include "asterisk/term.h"
107 #include "asterisk/manager.h"
108 #include "asterisk/cdr.h"
109 #include "asterisk/pbx.h"
110 #include "asterisk/enum.h"
111 #include "asterisk/rtp.h"
112 #include "asterisk/http.h"
113 #include "asterisk/udptl.h"
114 #include "asterisk/app.h"
115 #include "asterisk/lock.h"
116 #include "asterisk/utils.h"
117 #include "asterisk/file.h"
118 #include "asterisk/io.h"
119 #include "asterisk/lock.h"
120 #include "editline/histedit.h"
121 #include "asterisk/config.h"
122 #include "asterisk/version.h"
123 #include "asterisk/linkedlists.h"
124 #include "asterisk/devicestate.h"
126 #include "asterisk/doxyref.h" /* Doxygen documentation */
128 #include "../defaults.h"
131 #define AF_LOCAL AF_UNIX
132 #define PF_LOCAL PF_UNIX
135 #define AST_MAX_CONNECTS 128
138 /*! \brief Welcome message when starting a CLI interface */
139 #define WELCOME_MESSAGE \
140 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
141 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
142 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
143 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
144 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
145 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
146 ast_verbose("=========================================================================\n")
148 /*! \defgroup main_options
149 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
150 the operating system command line when starting Asterisk
151 Some of them can be changed in the CLI
155 extern int ast_language_is_prefix; /* XXX move to some header */
157 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
159 int option_verbose = 0; /*!< Verbosity level */
160 int option_debug = 0; /*!< Debug level */
162 double option_maxload = 0.0; /*!< Max load avg on system */
163 int option_maxcalls = 0; /*!< Max number of active calls */
167 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
168 char debug_filename[AST_FILENAME_MAX] = "";
170 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
171 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
174 int fd; /*!< File descriptor */
175 int p[2]; /*!< Pipe */
176 pthread_t t; /*!< Thread of handler */
177 int mute; /*!< Is the console muted for logs */
182 AST_LIST_ENTRY(ast_atexit) list;
185 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
187 time_t ast_startuptime;
188 time_t ast_lastreloadtime;
190 static History *el_hist = NULL;
191 static EditLine *el = NULL;
192 static char *remotehostname;
194 struct console consoles[AST_MAX_CONNECTS];
196 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
198 static int ast_el_add_history(char *);
199 static int ast_el_read_history(char *);
200 static int ast_el_write_history(char *);
202 char ast_config_AST_CONFIG_DIR[PATH_MAX];
203 char ast_config_AST_CONFIG_FILE[PATH_MAX];
204 char ast_config_AST_MODULE_DIR[PATH_MAX];
205 char ast_config_AST_SPOOL_DIR[PATH_MAX];
206 char ast_config_AST_MONITOR_DIR[PATH_MAX];
207 char ast_config_AST_VAR_DIR[PATH_MAX];
208 char ast_config_AST_DATA_DIR[PATH_MAX];
209 char ast_config_AST_LOG_DIR[PATH_MAX];
210 char ast_config_AST_AGI_DIR[PATH_MAX];
211 char ast_config_AST_DB[PATH_MAX];
212 char ast_config_AST_KEY_DIR[PATH_MAX];
213 char ast_config_AST_PID[PATH_MAX];
214 char ast_config_AST_SOCKET[PATH_MAX];
215 char ast_config_AST_RUN_DIR[PATH_MAX];
216 char ast_config_AST_RUN_USER[PATH_MAX];
217 char ast_config_AST_RUN_GROUP[PATH_MAX];
218 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
219 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
220 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
221 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
222 char ast_config_AST_SYSTEM_NAME[20] = "";
224 extern const char *ast_build_hostname;
225 extern const char *ast_build_kernel;
226 extern const char *ast_build_machine;
227 extern const char *ast_build_os;
228 extern const char *ast_build_date;
229 extern const char *ast_build_user;
231 static char *_argv[256];
232 static int shuttingdown = 0;
233 static int restartnow = 0;
234 static pthread_t consolethread = AST_PTHREADT_NULL;
236 static char randompool[256];
238 #if !defined(LOW_MEMORY)
239 struct file_version {
240 AST_LIST_ENTRY(file_version) list;
245 static AST_LIST_HEAD_STATIC(file_versions, file_version);
247 void ast_register_file_version(const char *file, const char *version)
249 struct file_version *new;
251 size_t version_length;
253 work = ast_strdupa(version);
254 work = ast_strip(ast_strip_quoted(work, "$", "$"));
255 version_length = strlen(work) + 1;
257 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
261 new->version = (char *) new + sizeof(*new);
262 memcpy(new->version, work, version_length);
263 AST_LIST_LOCK(&file_versions);
264 AST_LIST_INSERT_HEAD(&file_versions, new, list);
265 AST_LIST_UNLOCK(&file_versions);
268 void ast_unregister_file_version(const char *file)
270 struct file_version *find;
272 AST_LIST_LOCK(&file_versions);
273 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
274 if (!strcasecmp(find->file, file)) {
275 AST_LIST_REMOVE_CURRENT(&file_versions, list);
279 AST_LIST_TRAVERSE_SAFE_END;
280 AST_LIST_UNLOCK(&file_versions);
285 struct thread_list_t {
286 AST_LIST_ENTRY(thread_list_t) list;
291 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
293 static char show_threads_help[] =
294 "Usage: show threads\n"
295 " List threads currently active in the system.\n";
297 void ast_register_thread(char *name)
299 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
303 new->id = pthread_self();
304 new->name = name; /* this was a copy already */
305 AST_LIST_LOCK(&thread_list);
306 AST_LIST_INSERT_HEAD(&thread_list, new, list);
307 AST_LIST_UNLOCK(&thread_list);
310 void ast_unregister_thread(void *id)
312 struct thread_list_t *x;
314 AST_LIST_LOCK(&thread_list);
315 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
316 if ((void *)x->id == id) {
317 AST_LIST_REMOVE_CURRENT(&thread_list, list);
321 AST_LIST_TRAVERSE_SAFE_END;
322 AST_LIST_UNLOCK(&thread_list);
329 static int handle_show_threads(int fd, int argc, char *argv[])
332 struct thread_list_t *cur;
334 AST_LIST_LOCK(&thread_list);
335 AST_LIST_TRAVERSE(&thread_list, cur, list) {
336 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
339 AST_LIST_UNLOCK(&thread_list);
340 ast_cli(fd, "%d threads listed.\n", count);
344 struct profile_entry {
346 uint64_t scale; /* if non-zero, values are scaled by this */
352 struct profile_data {
355 struct profile_entry e[0];
358 static struct profile_data *prof_data;
360 /*! \brief allocates a counter with a given name and scale.
361 * \return Returns the identifier of the counter.
363 int ast_add_profile(const char *name, uint64_t scale)
365 int l = sizeof(struct profile_data);
366 int n = 10; /* default entries */
368 if (prof_data == NULL) {
369 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
370 if (prof_data == NULL)
372 prof_data->entries = 0;
373 prof_data->max_size = n;
375 if (prof_data->entries >= prof_data->max_size) {
377 n = prof_data->max_size + 20;
378 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
382 prof_data->max_size = n;
384 n = prof_data->entries++;
385 prof_data->e[n].name = ast_strdup(name);
386 prof_data->e[n].value = 0;
387 prof_data->e[n].events = 0;
388 prof_data->e[n].mark = 0;
389 prof_data->e[n].scale = scale;
393 int64_t ast_profile(int i, int64_t delta)
395 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
397 if (prof_data->e[i].scale > 1)
398 delta /= prof_data->e[i].scale;
399 prof_data->e[i].value += delta;
400 prof_data->e[i].events++;
401 return prof_data->e[i].value;
404 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
405 #if defined(__FreeBSD__)
406 #include <machine/cpufunc.h>
408 static __inline uint64_t
413 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
417 #else /* supply a dummy function on other platforms */
418 static __inline uint64_t
425 int64_t ast_mark(int i, int startstop)
427 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
430 prof_data->e[i].mark = rdtsc();
432 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
433 if (prof_data->e[i].scale > 1)
434 prof_data->e[i].mark /= prof_data->e[i].scale;
435 prof_data->e[i].value += prof_data->e[i].mark;
436 prof_data->e[i].events++;
438 return prof_data->e[i].mark;
441 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
446 if (prof_data == NULL)
450 max = prof_data->entries;
451 if (argc >= 3) { /* specific entries */
452 if (isdigit(argv[2][0])) {
454 if (argc == 4 && strcmp(argv[3], "-"))
459 if (max > prof_data->entries)
460 max = prof_data->entries;
461 if (!strcmp(argv[0], "clear")) {
462 for (i= min; i < max; i++) {
463 if (!search || strstr(prof_data->e[i].name, search)) {
464 prof_data->e[i].value = 0;
465 prof_data->e[i].events = 0;
470 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
471 prof_data->entries, prof_data->max_size);
472 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
473 "Value", "Average", "Name");
474 for (i = min; i < max; i++) {
475 struct profile_entry *e = &prof_data->e[i];
476 if (!search || strstr(prof_data->e[i].name, search))
477 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
480 (long)e->events, (long long)e->value,
481 (long long)(e->events ? e->value / e->events : e->value),
487 static int handle_show_profile(int fd, int argc, char *argv[])
492 if (prof_data == NULL)
496 max = prof_data->entries;
497 if (argc >= 3) { /* specific entries */
498 if (isdigit(argv[2][0])) {
500 if (argc == 4 && strcmp(argv[3], "-"))
505 if (max > prof_data->entries)
506 max = prof_data->entries;
507 if (!strcmp(argv[1], "clear")) {
508 for (i= min; i < max; i++) {
509 if (!search || strstr(prof_data->e[i].name, search)) {
510 prof_data->e[i].value = 0;
511 prof_data->e[i].events = 0;
516 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
517 prof_data->entries, prof_data->max_size);
518 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
519 "Value", "Average", "Name");
520 for (i = min; i < max; i++) {
521 struct profile_entry *e = &prof_data->e[i];
522 if (!search || strstr(prof_data->e[i].name, search))
523 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
526 (long)e->events, (long long)e->value,
527 (long long)(e->events ? e->value / e->events : e->value),
533 static char show_version_files_help[] =
534 "Usage: file list version [like <pattern>]\n"
535 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
536 " Optional regular expression pattern is used to filter the file list.\n";
538 /*! \brief CLI command to list module versions */
539 static int handle_show_version_files(int fd, int argc, char *argv[])
541 #define FORMAT "%-25.25s %-40.40s\n"
542 struct file_version *iterator;
550 if (!strcasecmp(argv[3], "like")) {
551 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
552 return RESULT_SHOWUSAGE;
555 return RESULT_SHOWUSAGE;
563 return RESULT_SHOWUSAGE;
566 ast_cli(fd, FORMAT, "File", "Revision");
567 ast_cli(fd, FORMAT, "----", "--------");
568 AST_LIST_LOCK(&file_versions);
569 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
570 if (havename && strcasecmp(iterator->file, argv[3]))
573 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
576 ast_cli(fd, FORMAT, iterator->file, iterator->version);
581 AST_LIST_UNLOCK(&file_versions);
583 ast_cli(fd, "%d files listed.\n", count_files);
589 return RESULT_SUCCESS;
593 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
595 struct file_version *find;
598 int matchlen = strlen(word);
603 AST_LIST_LOCK(&file_versions);
604 AST_LIST_TRAVERSE(&file_versions, find, list) {
605 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
606 ret = ast_strdup(find->file);
610 AST_LIST_UNLOCK(&file_versions);
614 #endif /* ! LOW_MEMORY */
616 int ast_register_atexit(void (*func)(void))
619 struct ast_atexit *ae;
620 ast_unregister_atexit(func);
621 AST_LIST_LOCK(&atexits);
622 if ((ae = ast_calloc(1, sizeof(*ae)))) {
623 AST_LIST_INSERT_HEAD(&atexits, ae, list);
627 AST_LIST_UNLOCK(&atexits);
631 void ast_unregister_atexit(void (*func)(void))
633 struct ast_atexit *ae;
634 AST_LIST_LOCK(&atexits);
635 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
636 if (ae->func == func) {
637 AST_LIST_REMOVE_CURRENT(&atexits, list);
641 AST_LIST_TRAVERSE_SAFE_END
642 AST_LIST_UNLOCK(&atexits);
645 static int fdprint(int fd, const char *s)
647 return write(fd, s, strlen(s) + 1);
650 /*! \brief NULL handler so we can collect the child exit status */
651 static void null_sig_handler(int signal)
656 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
657 /*! \brief Keep track of how many threads are currently trying to wait*() on
659 static unsigned int safe_system_level = 0;
660 static void *safe_system_prev_handler;
662 void ast_replace_sigchld(void)
666 ast_mutex_lock(&safe_system_lock);
667 level = safe_system_level++;
669 /* only replace the handler if it has not already been done */
671 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
673 ast_mutex_unlock(&safe_system_lock);
676 void ast_unreplace_sigchld(void)
680 ast_mutex_lock(&safe_system_lock);
681 level = --safe_system_level;
683 /* only restore the handler if we are the last one */
685 signal(SIGCHLD, safe_system_prev_handler);
687 ast_mutex_unlock(&safe_system_lock);
690 int ast_safe_system(const char *s)
695 struct rusage rusage;
698 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
699 ast_replace_sigchld();
701 #ifdef HAVE_WORKING_FORK
708 if (ast_opt_high_priority)
710 /* Close file descriptors and launch system command */
711 for (x = STDERR_FILENO + 1; x < 4096; x++)
713 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
715 } else if (pid > 0) {
717 res = wait4(pid, &status, 0, &rusage);
719 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
721 } else if (errno != EINTR)
725 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
729 ast_unreplace_sigchld();
738 * \brief mute or unmute a console from logging
740 void ast_console_toggle_mute(int fd) {
742 for (x = 0;x < AST_MAX_CONNECTS; x++) {
743 if (fd == consoles[x].fd) {
744 if (consoles[x].mute) {
745 consoles[x].mute = 0;
746 ast_cli(fd, "Console is not muted anymore.\n");
748 consoles[x].mute = 1;
749 ast_cli(fd, "Console is muted.\n");
754 ast_cli(fd, "Couldn't find remote console.\n");
758 * \brief log the string to all attached console clients
760 static void ast_network_puts_mutable(const char *string)
763 for (x = 0;x < AST_MAX_CONNECTS; x++) {
764 if (consoles[x].mute)
766 if (consoles[x].fd > -1)
767 fdprint(consoles[x].p[1], string);
772 * \brief log the string to the console, and all attached
775 void ast_console_puts_mutable(const char *string)
777 fputs(string, stdout);
779 ast_network_puts_mutable(string);
783 * \brief write the string to all attached console clients
785 static void ast_network_puts(const char *string)
788 for (x=0; x < AST_MAX_CONNECTS; x++) {
789 if (consoles[x].fd > -1)
790 fdprint(consoles[x].p[1], string);
795 * write the string to the console, and all attached
798 void ast_console_puts(const char *string)
800 fputs(string, stdout);
802 ast_network_puts(string);
805 static void network_verboser(const char *s)
807 ast_network_puts_mutable(s);
810 static pthread_t lthread;
812 static void *netconsole(void *vconsole)
814 struct console *con = vconsole;
815 char hostname[MAXHOSTNAMELEN] = "";
818 struct pollfd fds[2];
820 if (gethostname(hostname, sizeof(hostname)-1))
821 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
822 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
823 fdprint(con->fd, tmp);
826 fds[0].events = POLLIN;
828 fds[1].fd = con->p[0];
829 fds[1].events = POLLIN;
832 res = poll(fds, 2, -1);
835 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
838 if (fds[0].revents) {
839 res = read(con->fd, tmp, sizeof(tmp));
844 ast_cli_command(con->fd, tmp);
846 if (fds[1].revents) {
847 res = read(con->p[0], tmp, sizeof(tmp));
849 ast_log(LOG_ERROR, "read returned %d\n", res);
852 res = write(con->fd, tmp, res);
857 if (option_verbose > 2)
858 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
867 static void *listener(void *unused)
869 struct sockaddr_un sunaddr;
874 struct pollfd fds[1];
876 pthread_attr_init(&attr);
877 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
881 fds[0].fd = ast_socket;
882 fds[0].events = POLLIN;
883 s = poll(fds, 1, -1);
884 pthread_testcancel();
887 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
890 len = sizeof(sunaddr);
891 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
894 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
896 for (x = 0; x < AST_MAX_CONNECTS; x++) {
897 if (consoles[x].fd < 0) {
898 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
899 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
901 fdprint(s, "Server failed to create pipe\n");
905 flags = fcntl(consoles[x].p[1], F_GETFL);
906 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
908 consoles[x].mute = ast_opt_mute;
909 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
910 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
911 close(consoles[x].p[0]);
912 close(consoles[x].p[1]);
914 fdprint(s, "Server failed to spawn thread\n");
920 if (x >= AST_MAX_CONNECTS) {
921 fdprint(s, "No more connections allowed\n");
922 ast_log(LOG_WARNING, "No more connections allowed\n");
924 } else if (consoles[x].fd > -1) {
925 if (option_verbose > 2)
926 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
933 static int ast_makesocket(void)
935 struct sockaddr_un sunaddr;
941 for (x = 0; x < AST_MAX_CONNECTS; x++)
943 unlink(ast_config_AST_SOCKET);
944 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
945 if (ast_socket < 0) {
946 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
949 memset(&sunaddr, 0, sizeof(sunaddr));
950 sunaddr.sun_family = AF_LOCAL;
951 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
952 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
954 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
959 res = listen(ast_socket, 2);
961 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
966 ast_register_verbose(network_verboser);
967 ast_pthread_create(<hread, NULL, listener, NULL);
969 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
971 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
972 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
978 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
980 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
981 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
987 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
988 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
990 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
993 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
995 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
996 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1002 static int ast_tryconnect(void)
1004 struct sockaddr_un sunaddr;
1006 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1007 if (ast_consock < 0) {
1008 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1011 memset(&sunaddr, 0, sizeof(sunaddr));
1012 sunaddr.sun_family = AF_LOCAL;
1013 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1014 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1023 /*! \brief Urgent handler
1025 Called by soft_hangup to interrupt the poll, read, or other
1026 system call. We don't actually need to do anything though.
1027 Remember: Cannot EVER ast_log from within a signal handler
1029 static void urg_handler(int num)
1031 signal(num, urg_handler);
1035 static void hup_handler(int num)
1037 if (option_verbose > 1)
1038 printf("Received HUP signal -- Reloading configs\n");
1040 execvp(_argv[0], _argv);
1041 /* XXX This could deadlock XXX */
1042 ast_module_reload(NULL);
1043 signal(num, hup_handler);
1046 static void child_handler(int sig)
1048 /* Must not ever ast_log or ast_verbose within signal handler */
1052 * Reap all dead children -- not just one
1054 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1056 if (n == 0 && option_debug)
1057 printf("Huh? Child handler, but nobody there?\n");
1058 signal(sig, child_handler);
1061 /*! \brief Set an X-term or screen title */
1062 static void set_title(char *text)
1064 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1065 fprintf(stdout, "\033]2;%s\007", text);
1068 static void set_icon(char *text)
1070 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1071 fprintf(stdout, "\033]1;%s\007", text);
1074 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1075 else. If your PBX has heavy activity on it, this is a good thing. */
1076 int ast_set_priority(int pri)
1078 struct sched_param sched;
1079 memset(&sched, 0, sizeof(sched));
1082 sched.sched_priority = 10;
1083 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1084 ast_log(LOG_WARNING, "Unable to set high priority\n");
1088 ast_verbose("Set to realtime thread\n");
1090 sched.sched_priority = 0;
1091 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
1092 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1098 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1099 ast_log(LOG_WARNING, "Unable to set high priority\n");
1103 ast_verbose("Set to high priority\n");
1105 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1106 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1114 static void ast_run_atexits(void)
1116 struct ast_atexit *ae;
1117 AST_LIST_LOCK(&atexits);
1118 AST_LIST_TRAVERSE(&atexits, ae, list) {
1122 AST_LIST_UNLOCK(&atexits);
1125 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1127 char filename[80] = "";
1130 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1131 ast_cdr_engine_term();
1135 /* Begin shutdown routine, hanging up active channels */
1136 ast_begin_shutdown(1);
1137 if (option_verbose && ast_opt_console)
1138 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1142 /* Wait up to 15 seconds for all channels to go away */
1145 if (!ast_active_channels())
1149 /* Sleep 1/10 of a second */
1154 ast_begin_shutdown(0);
1155 if (option_verbose && ast_opt_console)
1156 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1158 if (!ast_active_channels())
1166 if (!shuttingdown) {
1167 if (option_verbose && ast_opt_console)
1168 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1172 if (ast_opt_console || ast_opt_remote) {
1174 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1175 if (!ast_strlen_zero(filename))
1176 ast_el_write_history(filename);
1179 if (el_hist != NULL)
1180 history_end(el_hist);
1183 ast_verbose("Executing last minute cleanups\n");
1185 /* Called on exit */
1186 if (option_verbose && ast_opt_console)
1187 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1188 else if (option_debug)
1189 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1190 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1191 if (ast_socket > -1) {
1192 pthread_cancel(lthread);
1195 unlink(ast_config_AST_SOCKET);
1197 if (ast_consock > -1)
1199 if (!ast_opt_remote)
1200 unlink(ast_config_AST_PID);
1201 printf(term_quit());
1203 if (option_verbose || ast_opt_console)
1204 ast_verbose("Preparing for Asterisk restart...\n");
1205 /* Mark all FD's for closing on exec */
1206 for (x=3; x < 32768; x++) {
1207 fcntl(x, F_SETFD, FD_CLOEXEC);
1209 if (option_verbose || ast_opt_console)
1210 ast_verbose("Restarting Asterisk NOW...\n");
1216 /* If there is a consolethread running send it a SIGHUP
1217 so it can execvp, otherwise we can do it ourselves */
1218 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1219 pthread_kill(consolethread, SIGHUP);
1220 /* Give the signal handler some time to complete */
1223 execvp(_argv[0], _argv);
1232 static void __quit_handler(int num)
1234 quit_handler(num, 0, 1, 0);
1237 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1240 if (!strncmp(s, cmp, strlen(cmp))) {
1241 c = s + strlen(cmp);
1242 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1248 static void console_verboser(const char *s)
1251 const char *c = NULL;
1253 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1254 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1255 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1256 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1264 /* Wake up a poll()ing console */
1265 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1266 pthread_kill(consolethread, SIGURG);
1269 static int ast_all_zeros(char *s)
1279 static void consolehandler(char *s)
1284 /* Called when readline data is available */
1285 if (!ast_all_zeros(s))
1286 ast_el_add_history(s);
1287 /* The real handler for bang */
1290 ast_safe_system(s+1);
1292 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1294 ast_cli_command(STDOUT_FILENO, s);
1297 static int remoteconsolehandler(char *s)
1301 /* Called when readline data is available */
1302 if (!ast_all_zeros(s))
1303 ast_el_add_history(s);
1304 /* The real handler for bang */
1307 ast_safe_system(s+1);
1309 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1312 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1313 (s[4] == '\0' || isspace(s[4]))) {
1314 quit_handler(0, 0, 0, 0);
1321 static char abort_halt_help[] =
1322 "Usage: abort shutdown\n"
1323 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1324 " call operations.\n";
1326 static char shutdown_now_help[] =
1328 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1330 static char shutdown_gracefully_help[] =
1331 "Usage: stop gracefully\n"
1332 " Causes Asterisk to not accept new calls, and exit when all\n"
1333 " active calls have terminated normally.\n";
1335 static char shutdown_when_convenient_help[] =
1336 "Usage: stop when convenient\n"
1337 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1339 static char restart_now_help[] =
1340 "Usage: restart now\n"
1341 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1344 static char restart_gracefully_help[] =
1345 "Usage: restart gracefully\n"
1346 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1347 " restart when all active calls have ended.\n";
1349 static char restart_when_convenient_help[] =
1350 "Usage: restart when convenient\n"
1351 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1353 static char bang_help[] =
1354 "Usage: !<command>\n"
1355 " Executes a given shell command\n";
1357 static char show_warranty_help[] =
1358 "Usage: show warranty\n"
1359 " Shows the warranty (if any) for this copy of Asterisk.\n";
1361 static char show_license_help[] =
1362 "Usage: show license\n"
1363 " Shows the license(s) for this copy of Asterisk.\n";
1365 static char version_help[] =
1366 "Usage: show version\n"
1367 " Shows Asterisk version information.\n";
1369 static int handle_version(int fd, int argc, char *argv[])
1372 return RESULT_SHOWUSAGE;
1373 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1374 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1375 ast_build_machine, ast_build_os, ast_build_date);
1376 return RESULT_SUCCESS;
1380 static int handle_quit(int fd, int argc, char *argv[])
1383 return RESULT_SHOWUSAGE;
1384 quit_handler(0, 0, 1, 0);
1385 return RESULT_SUCCESS;
1389 static int handle_shutdown_now(int fd, int argc, char *argv[])
1392 return RESULT_SHOWUSAGE;
1393 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1394 return RESULT_SUCCESS;
1397 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1400 return RESULT_SHOWUSAGE;
1401 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1402 return RESULT_SUCCESS;
1405 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1408 return RESULT_SHOWUSAGE;
1409 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1410 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1411 return RESULT_SUCCESS;
1414 static int handle_restart_now(int fd, int argc, char *argv[])
1417 return RESULT_SHOWUSAGE;
1418 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1419 return RESULT_SUCCESS;
1422 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1425 return RESULT_SHOWUSAGE;
1426 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1427 return RESULT_SUCCESS;
1430 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1433 return RESULT_SHOWUSAGE;
1434 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1435 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1436 return RESULT_SUCCESS;
1439 static int handle_abort_halt(int fd, int argc, char *argv[])
1442 return RESULT_SHOWUSAGE;
1443 ast_cancel_shutdown();
1445 return RESULT_SUCCESS;
1448 static int handle_bang(int fd, int argc, char *argv[])
1450 return RESULT_SUCCESS;
1452 static const char *warranty_lines[] = {
1456 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1457 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1458 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1459 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1460 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1461 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1462 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1463 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1464 "REPAIR OR CORRECTION.\n",
1466 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1467 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1468 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1469 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1470 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1471 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1472 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1473 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1474 "POSSIBILITY OF SUCH DAMAGES.\n",
1477 static int show_warranty(int fd, int argc, char *argv[])
1481 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1482 ast_cli(fd, (char *) warranty_lines[x]);
1484 return RESULT_SUCCESS;
1487 static const char *license_lines[] = {
1489 "This program is free software; you can redistribute it and/or modify\n",
1490 "it under the terms of the GNU General Public License version 2 as\n",
1491 "published by the Free Software Foundation.\n",
1493 "This program also contains components licensed under other licenses.\n",
1496 "This program is distributed in the hope that it will be useful,\n",
1497 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1498 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1499 "GNU General Public License for more details.\n",
1501 "You should have received a copy of the GNU General Public License\n",
1502 "along with this program; if not, write to the Free Software\n",
1503 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1506 static int show_license(int fd, int argc, char *argv[])
1510 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1511 ast_cli(fd, (char *) license_lines[x]);
1513 return RESULT_SUCCESS;
1516 #define ASTERISK_PROMPT "*CLI> "
1518 #define ASTERISK_PROMPT2 "%s*CLI> "
1520 #if !defined(LOW_MEMORY)
1521 static struct ast_cli_entry cli_show_version_files_deprecated = {
1522 { "show", "version", "files", NULL },
1523 handle_show_version_files, NULL,
1524 NULL, complete_show_version_files };
1526 static struct ast_cli_entry cli_show_profile_deprecated = {
1527 { "show", "profile", NULL },
1528 handle_show_profile_deprecated, NULL,
1531 static struct ast_cli_entry cli_clear_profile_deprecated = {
1532 { "clear", "profile", NULL },
1533 handle_show_profile_deprecated, NULL,
1535 #endif /* ! LOW_MEMORY */
1537 static struct ast_cli_entry cli_asterisk[] = {
1538 { { "abort", "halt", NULL },
1539 handle_abort_halt, "Cancel a running halt",
1542 { { "stop", "now", NULL },
1543 handle_shutdown_now, "Shut down Asterisk immediately",
1544 shutdown_now_help },
1546 { { "stop", "gracefully", NULL },
1547 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1548 shutdown_gracefully_help },
1550 { { "stop", "when", "convenient", NULL },
1551 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1552 shutdown_when_convenient_help },
1554 { { "restart", "now", NULL },
1555 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1557 { { "restart", "gracefully", NULL },
1558 handle_restart_gracefully, "Restart Asterisk gracefully",
1559 restart_gracefully_help },
1561 { { "restart", "when", "convenient", NULL },
1562 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1563 restart_when_convenient_help },
1565 { { "show", "warranty", NULL },
1566 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1567 show_warranty_help },
1569 { { "show", "license", NULL },
1570 show_license, "Show the license(s) for this copy of Asterisk",
1571 show_license_help },
1573 { { "show", "version", NULL },
1574 handle_version, "Display version info",
1578 handle_bang, "Execute a shell command",
1581 #if !defined(LOW_MEMORY)
1582 { { "file", "list", "version", NULL },
1583 handle_show_version_files, "List versions of files used to build Asterisk",
1584 show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
1586 { { "show", "threads", NULL },
1587 handle_show_threads, "Show running threads",
1588 show_threads_help },
1590 { { "profile", "list", NULL },
1591 handle_show_profile, "Display profiling info",
1592 NULL, NULL, &cli_show_profile_deprecated },
1594 { { "profile", "clear", NULL },
1595 handle_show_profile, "Clear profiling info",
1596 NULL, NULL, &cli_clear_profile_deprecated },
1597 #endif /* ! LOW_MEMORY */
1600 static int ast_el_read_char(EditLine *el, char *cp)
1604 struct pollfd fds[2];
1611 fds[0].fd = ast_consock;
1612 fds[0].events = POLLIN;
1613 if (!ast_opt_exec) {
1614 fds[1].fd = STDIN_FILENO;
1615 fds[1].events = POLLIN;
1618 res = poll(fds, max, -1);
1622 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1626 if (!ast_opt_exec && fds[1].revents) {
1627 num_read = read(STDIN_FILENO, cp, 1);
1633 if (fds[0].revents) {
1634 res = read(ast_consock, buf, sizeof(buf) - 1);
1635 /* if the remote side disappears exit */
1637 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1638 if (!ast_opt_reconnect) {
1639 quit_handler(0, 0, 0, 0);
1642 int reconnects_per_second = 20;
1643 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1644 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1645 if (ast_tryconnect()) {
1646 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1647 printf(term_quit());
1651 usleep(1000000 / reconnects_per_second);
1654 if (tries >= 30 * reconnects_per_second) {
1655 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1656 quit_handler(0, 0, 0, 0);
1663 if (!ast_opt_exec && !lastpos)
1664 write(STDOUT_FILENO, "\r", 1);
1665 write(STDOUT_FILENO, buf, res);
1666 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1679 static char *cli_prompt(EditLine *el)
1681 static char prompt[200];
1686 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1687 char *t = pfmt, *p = prompt;
1688 memset(prompt, 0, sizeof(prompt));
1689 while (*t != '\0' && *p < sizeof(prompt)) {
1691 char hostname[MAXHOSTNAMELEN]="";
1698 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1702 case 'C': /* color */
1704 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1705 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1707 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1708 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1712 /* If the color has been reset correctly, then there's no need to reset it later */
1713 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1719 case 'd': /* date */
1720 memset(&tm, 0, sizeof(tm));
1722 if (localtime_r(&ts, &tm)) {
1723 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1726 case 'h': /* hostname */
1727 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1728 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1730 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1733 case 'H': /* short hostname */
1734 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1735 for (i = 0; i < sizeof(hostname); i++) {
1736 if (hostname[i] == '.') {
1741 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1743 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1747 case 'l': /* load avg */
1749 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1750 float avg1, avg2, avg3;
1751 int actproc, totproc, npid, which;
1752 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1753 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1754 if (sscanf(t, "%d", &which) == 1) {
1757 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1760 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1763 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1766 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1769 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1776 case 's': /* Asterisk system name (from asterisk.conf) */
1777 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1779 case 't': /* time */
1780 memset(&tm, 0, sizeof(tm));
1782 if (localtime_r(&ts, &tm)) {
1783 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1786 case '#': /* process console or remote? */
1787 if (!ast_opt_remote) {
1788 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1790 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1793 case '%': /* literal % */
1794 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1796 case '\0': /* % is last character - prevent bug */
1800 while (*p != '\0') {
1811 /* Force colors back to normal at end */
1812 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1813 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1814 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1816 strncat(p, term_code, sizeof(term_code));
1819 } else if (remotehostname)
1820 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1822 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1827 static char **ast_el_strtoarr(char *buf)
1829 char **match_list = NULL, *retstr;
1830 size_t match_list_len;
1834 while ( (retstr = strsep(&buf, " ")) != NULL) {
1836 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1838 if (matches + 1 >= match_list_len) {
1839 match_list_len <<= 1;
1840 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1841 /* TODO: Handle memory allocation failure */
1845 match_list[matches++] = strdup(retstr);
1849 return (char **) NULL;
1851 if (matches >= match_list_len) {
1852 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1853 /* TODO: Handle memory allocation failure */
1857 match_list[matches] = (char *) NULL;
1862 static int ast_el_sort_compare(const void *i1, const void *i2)
1866 s1 = ((char **)i1)[0];
1867 s2 = ((char **)i2)[0];
1869 return strcasecmp(s1, s2);
1872 static int ast_cli_display_match_list(char **matches, int len, int max)
1874 int i, idx, limit, count;
1875 int screenwidth = 0;
1876 int numoutput = 0, numoutputline = 0;
1878 screenwidth = ast_get_termcols(STDOUT_FILENO);
1880 /* find out how many entries can be put on one line, with two spaces between strings */
1881 limit = screenwidth / (max + 2);
1885 /* how many lines of output */
1886 count = len / limit;
1887 if (count * limit < len)
1892 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1894 for (; count > 0; count--) {
1896 for (i=0; i < limit && matches[idx]; i++, idx++) {
1898 /* Don't print dupes */
1899 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1902 matches[idx] = NULL;
1908 fprintf(stdout, "%-*s ", max, matches[idx]);
1910 matches[idx] = NULL;
1912 if (numoutputline > 0)
1913 fprintf(stdout, "\n");
1920 static char *cli_complete(EditLine *el, int ch)
1926 int retval = CC_ERROR;
1930 LineInfo *lf = (LineInfo *)el_line(el);
1932 *(char *)lf->cursor = '\0';
1933 ptr = (char *)lf->cursor;
1935 while (ptr > lf->buffer) {
1936 if (isspace(*ptr)) {
1944 len = lf->cursor - ptr;
1946 if (ast_opt_remote) {
1947 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1948 fdprint(ast_consock, buf);
1949 res = read(ast_consock, buf, sizeof(buf));
1951 nummatches = atoi(buf);
1953 if (nummatches > 0) {
1955 int mlen = 0, maxmbuf = 2048;
1956 /* Start with a 2048 byte buffer */
1957 if (!(mbuf = ast_malloc(maxmbuf)))
1958 return (char *)(CC_ERROR);
1959 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1960 fdprint(ast_consock, buf);
1963 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1964 if (mlen + 1024 > maxmbuf) {
1965 /* Every step increment buffer 1024 bytes */
1967 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1968 return (char *)(CC_ERROR);
1970 /* Only read 1024 bytes at a time */
1971 res = read(ast_consock, mbuf + mlen, 1024);
1977 matches = ast_el_strtoarr(mbuf);
1980 matches = (char **) NULL;
1982 char **p, *oldbuf=NULL;
1984 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1985 for (p = matches; p && *p; p++) {
1986 if (!oldbuf || strcmp(*p,oldbuf))
1994 int matches_num, maxlen, match_len;
1996 if (matches[0][0] != '\0') {
1997 el_deletestr(el, (int) len);
1998 el_insertstr(el, matches[0]);
1999 retval = CC_REFRESH;
2002 if (nummatches == 1) {
2003 /* Found an exact match */
2004 el_insertstr(el, " ");
2005 retval = CC_REFRESH;
2007 /* Must be more than one match */
2008 for (i=1, maxlen=0; matches[i]; i++) {
2009 match_len = strlen(matches[i]);
2010 if (match_len > maxlen)
2013 matches_num = i - 1;
2014 if (matches_num >1) {
2015 fprintf(stdout, "\n");
2016 ast_cli_display_match_list(matches, nummatches, maxlen);
2017 retval = CC_REDISPLAY;
2019 el_insertstr(el," ");
2020 retval = CC_REFRESH;
2026 return (char *)(long)retval;
2029 static int ast_el_initialize(void)
2032 char *editor = getenv("AST_EDITOR");
2036 if (el_hist != NULL)
2037 history_end(el_hist);
2039 el = el_init("asterisk", stdin, stdout, stderr);
2040 el_set(el, EL_PROMPT, cli_prompt);
2042 el_set(el, EL_EDITMODE, 1);
2043 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2044 el_hist = history_init();
2045 if (!el || !el_hist)
2048 /* setup history with 100 entries */
2049 history(el_hist, &ev, H_SETSIZE, 100);
2051 el_set(el, EL_HIST, history, el_hist);
2053 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2054 /* Bind <tab> to command completion */
2055 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2056 /* Bind ? to command completion */
2057 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2058 /* Bind ^D to redisplay */
2059 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2064 static int ast_el_add_history(char *buf)
2068 if (el_hist == NULL || el == NULL)
2069 ast_el_initialize();
2070 if (strlen(buf) > 256)
2072 return (history(el_hist, &ev, H_ENTER, buf));
2075 static int ast_el_write_history(char *filename)
2079 if (el_hist == NULL || el == NULL)
2080 ast_el_initialize();
2082 return (history(el_hist, &ev, H_SAVE, filename));
2085 static int ast_el_read_history(char *filename)
2091 if (el_hist == NULL || el == NULL)
2092 ast_el_initialize();
2094 if ((f = fopen(filename, "r")) == NULL)
2098 fgets(buf, sizeof(buf), f);
2099 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2101 if (ast_all_zeros(buf))
2103 if ((ret = ast_el_add_history(buf)) == -1)
2111 static void ast_remotecontrol(char * data)
2115 char filename[80] = "";
2121 char *stringp = NULL;
2126 read(ast_consock, buf, sizeof(buf));
2128 write(ast_consock, data, strlen(data) + 1);
2130 hostname = strsep(&stringp, "/");
2131 cpid = strsep(&stringp, "/");
2132 version = strsep(&stringp, "\n");
2134 version = "<Version Unknown>";
2136 strsep(&stringp, ".");
2141 snprintf(tmp, sizeof(tmp), "core verbose %d", option_verbose);
2142 fdprint(ast_consock, tmp);
2143 snprintf(tmp, sizeof(tmp), "core debug %d", option_debug);
2144 fdprint(ast_consock, tmp);
2146 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2147 fdprint(ast_consock, tmp);
2149 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2150 remotehostname = hostname;
2152 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2153 if (el_hist == NULL || el == NULL)
2154 ast_el_initialize();
2156 el_set(el, EL_GETCFN, ast_el_read_char);
2158 if (!ast_strlen_zero(filename))
2159 ast_el_read_history(filename);
2161 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2164 fds.fd = ast_consock;
2165 fds.events = POLLIN;
2167 while (poll(&fds, 1, 100) > 0)
2168 ast_el_read_char(el, &tempchar);
2172 ebuf = (char *)el_gets(el, &num);
2174 if (!ast_strlen_zero(ebuf)) {
2175 if (ebuf[strlen(ebuf)-1] == '\n')
2176 ebuf[strlen(ebuf)-1] = '\0';
2177 if (!remoteconsolehandler(ebuf)) {
2178 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2180 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2186 printf("\nDisconnected from Asterisk server\n");
2189 static int show_version(void)
2191 printf("Asterisk " ASTERISK_VERSION "\n");
2195 static int show_cli_help(void) {
2196 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2197 printf("Usage: asterisk [OPTIONS]\n");
2198 printf("Valid Options:\n");
2199 printf(" -V Display version number and exit\n");
2200 printf(" -C <configfile> Use an alternate configuration file\n");
2201 printf(" -G <group> Run as a group other than the caller\n");
2202 printf(" -U <user> Run as a user other than the caller\n");
2203 printf(" -c Provide console CLI\n");
2204 printf(" -d Enable extra debugging\n");
2205 #if HAVE_WORKING_FORK
2206 printf(" -f Do not fork\n");
2207 printf(" -F Always fork\n");
2209 printf(" -g Dump core in case of a crash\n");
2210 printf(" -h This help screen\n");
2211 printf(" -i Initialize crypto keys at startup\n");
2212 printf(" -I Enable internal timing if Zaptel timer is available\n");
2213 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2214 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2215 printf(" -m Mute the console from debugging and verbose output\n");
2216 printf(" -n Disable console colorization\n");
2217 printf(" -p Run as pseudo-realtime thread\n");
2218 printf(" -q Quiet mode (suppress output)\n");
2219 printf(" -r Connect to Asterisk on this machine\n");
2220 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2221 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2222 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2223 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2224 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2229 static void ast_readconfig(void)
2231 struct ast_config *cfg;
2232 struct ast_variable *v;
2233 char *config = AST_CONFIG_FILE;
2235 if (ast_opt_override_config) {
2236 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2238 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2240 cfg = ast_config_load(config);
2243 /* init with buildtime config */
2244 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2245 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2246 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2247 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2248 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2249 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2250 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2251 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2252 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2253 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2254 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2255 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2256 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2258 /* no asterisk.conf? no problem, use buildtime config! */
2263 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2264 if (!strcasecmp(v->name, "astctlpermissions")) {
2265 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2266 } else if (!strcasecmp(v->name, "astctlowner")) {
2267 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2268 } else if (!strcasecmp(v->name, "astctlgroup")) {
2269 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2270 } else if (!strcasecmp(v->name, "astctl")) {
2271 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2275 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2276 if (!strcasecmp(v->name, "astetcdir")) {
2277 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2278 } else if (!strcasecmp(v->name, "astspooldir")) {
2279 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2280 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2281 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2282 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2283 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2284 } else if (!strcasecmp(v->name, "astdatadir")) {
2285 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2286 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2287 } else if (!strcasecmp(v->name, "astlogdir")) {
2288 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2289 } else if (!strcasecmp(v->name, "astagidir")) {
2290 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2291 } else if (!strcasecmp(v->name, "astrundir")) {
2292 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2293 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2294 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2295 } else if (!strcasecmp(v->name, "astmoddir")) {
2296 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2300 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2301 /* verbose level (-v at startup) */
2302 if (!strcasecmp(v->name, "verbose")) {
2303 option_verbose = atoi(v->value);
2304 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2305 } else if (!strcasecmp(v->name, "timestamp")) {
2306 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2307 /* whether or not to support #exec in config files */
2308 } else if (!strcasecmp(v->name, "execincludes")) {
2309 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2310 /* debug level (-d at startup) */
2311 } else if (!strcasecmp(v->name, "debug")) {
2313 if (sscanf(v->value, "%d", &option_debug) != 1) {
2314 option_debug = ast_true(v->value);
2316 #if HAVE_WORKING_FORK
2317 /* Disable forking (-f at startup) */
2318 } else if (!strcasecmp(v->name, "nofork")) {
2319 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2320 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2321 } else if (!strcasecmp(v->name, "alwaysfork")) {
2322 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2324 /* Run quietly (-q at startup ) */
2325 } else if (!strcasecmp(v->name, "quiet")) {
2326 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2327 /* Run as console (-c at startup, implies nofork) */
2328 } else if (!strcasecmp(v->name, "console")) {
2329 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2330 /* Run with high priority if the O/S permits (-p at startup) */
2331 } else if (!strcasecmp(v->name, "highpriority")) {
2332 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2333 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2334 } else if (!strcasecmp(v->name, "initcrypto")) {
2335 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2336 /* Disable ANSI colors for console (-c at startup) */
2337 } else if (!strcasecmp(v->name, "nocolor")) {
2338 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2339 /* Disable some usage warnings for picky people :p */
2340 } else if (!strcasecmp(v->name, "dontwarn")) {
2341 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2342 /* Dump core in case of crash (-g) */
2343 } else if (!strcasecmp(v->name, "dumpcore")) {
2344 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2345 /* Cache recorded sound files to another directory during recording */
2346 } else if (!strcasecmp(v->name, "cache_record_files")) {
2347 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2348 /* Specify cache directory */
2349 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2350 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2351 /* Build transcode paths via SLINEAR, instead of directly */
2352 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2353 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2354 /* Transmit SLINEAR silence while a channel is being recorded */
2355 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2356 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2357 /* Enable internal timing */
2358 } else if (!strcasecmp(v->name, "internal_timing")) {
2359 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2360 } else if (!strcasecmp(v->name, "maxcalls")) {
2361 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2362 option_maxcalls = 0;
2364 } else if (!strcasecmp(v->name, "maxload")) {
2367 if (getloadavg(test, 1) == -1) {
2368 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2369 option_maxload = 0.0;
2370 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2371 option_maxload = 0.0;
2373 /* What user to run as */
2374 } else if (!strcasecmp(v->name, "runuser")) {
2375 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2376 /* What group to run as */
2377 } else if (!strcasecmp(v->name, "rungroup")) {
2378 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2379 } else if (!strcasecmp(v->name, "systemname")) {
2380 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2381 } else if (!strcasecmp(v->name, "languageprefix")) {
2382 ast_language_is_prefix = ast_true(v->value);
2385 ast_config_destroy(cfg);
2388 int main(int argc, char *argv[])
2391 char filename[80] = "";
2392 char hostname[MAXHOSTNAMELEN] = "";
2399 int is_child_of_nonroot = 0;
2401 char *runuser = NULL, *rungroup = NULL;
2403 /* Remember original args for restart */
2404 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2405 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2406 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2408 for (x=0; x<argc; x++)
2412 /* if the progname is rasterisk consider it a remote console */
2413 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2414 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2416 if (gethostname(hostname, sizeof(hostname)-1))
2417 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2418 ast_mainpid = getpid();
2422 ast_builtins_init();
2425 /* When Asterisk restarts after it has dropped the root privileges,
2426 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2428 if (getenv("ASTERISK_ALREADY_NONROOT"))
2429 is_child_of_nonroot=1;
2431 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2432 /* Check for options */
2433 while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2435 #if HAVE_WORKING_FORK
2437 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2440 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2445 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2448 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2451 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2454 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2457 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2460 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2464 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2467 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2470 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2471 option_maxcalls = 0;
2474 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2475 option_maxload = 0.0;
2478 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2481 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2484 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2487 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2491 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2492 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2495 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2498 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2501 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2520 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2521 ast_register_verbose(console_verboser);
2525 if (ast_opt_console && !option_verbose)
2526 ast_verbose("[ Booting...\n");
2528 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2529 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2530 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2533 /* For remote connections, change the name of the remote connection.
2534 * We do this for the benefit of init scripts (which need to know if/when
2535 * the main asterisk process has died yet). */
2536 if (ast_opt_remote) {
2537 strcpy(argv[0], "rasterisk");
2538 for (x = 1; x < argc; x++) {
2539 argv[x] = argv[0] + 10;
2543 if (ast_opt_console && !option_verbose)
2544 ast_verbose("[ Reading Master Configuration ]\n");
2547 if (ast_opt_dump_core) {
2549 memset(&l, 0, sizeof(l));
2550 l.rlim_cur = RLIM_INFINITY;
2551 l.rlim_max = RLIM_INFINITY;
2552 if (setrlimit(RLIMIT_CORE, &l)) {
2553 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2557 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2558 rungroup = ast_config_AST_RUN_GROUP;
2559 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2560 runuser = ast_config_AST_RUN_USER;
2564 if (!is_child_of_nonroot)
2565 ast_set_priority(ast_opt_high_priority);
2567 if (!is_child_of_nonroot && rungroup) {
2569 gr = getgrnam(rungroup);
2571 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2574 if (setgid(gr->gr_gid)) {
2575 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2578 if (setgroups(0, NULL)) {
2579 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2583 ast_verbose("Running as group '%s'\n", rungroup);
2586 if (!is_child_of_nonroot && runuser) {
2588 pw = getpwnam(runuser);
2590 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2594 if (setgid(pw->pw_gid)) {
2595 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2598 if (initgroups(pw->pw_name, pw->pw_gid)) {
2599 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2603 if (setuid(pw->pw_uid)) {
2604 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2607 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2609 ast_verbose("Running as user '%s'\n", runuser);
2612 #endif /* __CYGWIN__ */
2615 if (geteuid() && ast_opt_dump_core) {
2616 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2617 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2626 if (ast_opt_console && !option_verbose)
2627 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2628 /* custom config setup */
2629 register_config_cli();
2632 if (ast_opt_console) {
2633 if (el_hist == NULL || el == NULL)
2634 ast_el_initialize();
2636 if (!ast_strlen_zero(filename))
2637 ast_el_read_history(filename);
2640 if (ast_tryconnect()) {
2641 /* One is already running */
2642 if (ast_opt_remote) {
2644 ast_remotecontrol(xarg);
2645 quit_handler(0, 0, 0, 0);
2648 printf(term_quit());
2649 ast_remotecontrol(NULL);
2650 quit_handler(0, 0, 0, 0);
2653 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2654 printf(term_quit());
2657 } else if (ast_opt_remote || ast_opt_exec) {
2658 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2659 printf(term_quit());
2662 /* Blindly write pid file since we couldn't connect */
2663 unlink(ast_config_AST_PID);
2664 f = fopen(ast_config_AST_PID, "w");
2666 fprintf(f, "%ld\n", (long)getpid());
2669 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2671 #if HAVE_WORKING_FORK
2672 if (ast_opt_always_fork || !ast_opt_no_fork) {
2674 ast_mainpid = getpid();
2675 /* Blindly re-write pid file since we are forking */
2676 unlink(ast_config_AST_PID);
2677 f = fopen(ast_config_AST_PID, "w");
2679 fprintf(f, "%ld\n", (long)ast_mainpid);
2682 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2686 /* Test recursive mutex locking. */
2687 if (test_for_thread_safety())
2688 ast_verbose("Warning! Asterisk is not thread safe.\n");
2692 sigaddset(&sigs, SIGHUP);
2693 sigaddset(&sigs, SIGTERM);
2694 sigaddset(&sigs, SIGINT);
2695 sigaddset(&sigs, SIGPIPE);
2696 sigaddset(&sigs, SIGWINCH);
2697 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2698 signal(SIGURG, urg_handler);
2699 signal(SIGINT, __quit_handler);
2700 signal(SIGTERM, __quit_handler);
2701 signal(SIGHUP, hup_handler);
2702 signal(SIGCHLD, child_handler);
2703 signal(SIGPIPE, SIG_IGN);
2705 /* ensure that the random number generators are seeded with a different value every time
2708 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2709 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2711 if (init_logger()) {
2712 printf(term_quit());
2715 if (load_modules(1)) {
2716 printf(term_quit());
2720 if (dnsmgr_init()) {
2721 printf(term_quit());
2727 ast_channels_init();
2729 if (init_manager()) {
2730 printf(term_quit());
2734 if (ast_cdr_engine_init()) {
2735 printf(term_quit());
2739 if (ast_device_state_engine_init()) {
2740 printf(term_quit());
2748 if (ast_image_init()) {
2749 printf(term_quit());
2753 if (ast_file_init()) {
2754 printf(term_quit());
2759 printf(term_quit());
2763 if (init_framer()) {
2764 printf(term_quit());
2769 printf(term_quit());
2773 if (ast_enum_init()) {
2774 printf(term_quit());
2778 if (load_modules(0)) {
2779 printf(term_quit());
2783 dnsmgr_start_refresh();
2785 /* We might have the option of showing a console, but for now just
2787 if (ast_opt_console && !option_verbose)
2788 ast_verbose(" ]\n");
2789 if (option_verbose || ast_opt_console)
2790 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2791 if (ast_opt_no_fork)
2792 consolethread = pthread_self();
2794 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2795 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2797 #ifdef __AST_DEBUG_MALLOC
2801 time(&ast_startuptime);
2802 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
2804 if (ast_opt_console) {
2805 /* Console stuff now... */
2806 /* Register our quit function */
2808 set_icon("Asterisk");
2809 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2813 buf = (char *)el_gets(el, &num);
2815 if (buf[strlen(buf)-1] == '\n')
2816 buf[strlen(buf)-1] = '\0';
2818 consolehandler((char *)buf);
2820 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2821 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2822 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2824 fd = open("/dev/null", O_RDWR);
2826 dup2(fd, STDOUT_FILENO);
2827 dup2(fd, STDIN_FILENO);
2829 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2837 for (;;) { /* apparently needed for Mac OS X */
2838 struct pollfd p = { -1 /* no descriptor */, 0, 0 };