Merged revisions 37441-37442 via svnmerge from
[asterisk-bristuff.git] / asterisk.c
blob69af7d4cb3fa1c6209e7a120475980da7dbc5a42
1 /*
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 */
21 /*!
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
28 * \arg \ref DevDoc
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
54 /*! \file
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
60 #include "asterisk.h"
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
64 #include <unistd.h>
65 #include <stdlib.h>
66 #include <sys/time.h>
67 #include <fcntl.h>
68 #include <stdio.h>
69 #include <signal.h>
70 #include <sched.h>
71 #include <sys/socket.h>
72 #include <sys/un.h>
73 #include <sys/wait.h>
74 #include <string.h>
75 #include <errno.h>
76 #include <ctype.h>
77 #include <sys/resource.h>
78 #include <grp.h>
79 #include <pwd.h>
80 #include <sys/stat.h>
81 #ifdef linux
82 #include <sys/prctl.h>
83 #endif
84 #include <regex.h>
86 #ifdef linux
87 #include <sys/prctl.h>
88 #endif
90 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
91 #include <netdb.h>
92 #if defined(SOLARIS)
93 int daemon(int, int); /* defined in libresolv of all places */
94 #endif
95 #endif
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"
130 #ifndef AF_LOCAL
131 #define AF_LOCAL AF_UNIX
132 #define PF_LOCAL PF_UNIX
133 #endif
135 #define AST_MAX_CONNECTS 128
136 #define NUM_MSGS 64
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
153 /*! @{ */
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 */
165 /*! @} */
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 */
172 pid_t ast_mainpid;
173 struct console {
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 */
180 struct ast_atexit {
181 void (*func)(void);
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;
241 const char *file;
242 char *version;
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;
250 char *work;
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)))
258 return;
260 new->file = file;
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);
276 break;
279 AST_LIST_TRAVERSE_SAFE_END;
280 AST_LIST_UNLOCK(&file_versions);
281 if (find)
282 free(find);
285 struct thread_list_t {
286 AST_LIST_ENTRY(thread_list_t) list;
287 char *name;
288 pthread_t id;
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));
301 if (!new)
302 return;
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);
318 break;
321 AST_LIST_TRAVERSE_SAFE_END;
322 AST_LIST_UNLOCK(&thread_list);
323 if (x) {
324 free(x->name);
325 free(x);
329 static int handle_show_threads(int fd, int argc, char *argv[])
331 int count = 0;
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);
337 count++;
339 AST_LIST_UNLOCK(&thread_list);
340 ast_cli(fd, "%d threads listed.\n", count);
341 return 0;
344 struct profile_entry {
345 const char *name;
346 uint64_t scale; /* if non-zero, values are scaled by this */
347 int64_t mark;
348 int64_t value;
349 int64_t events;
352 struct profile_data {
353 int entries;
354 int max_size;
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)
371 return -1;
372 prof_data->entries = 0;
373 prof_data->max_size = n;
375 if (prof_data->entries >= prof_data->max_size) {
376 void *p;
377 n = prof_data->max_size + 20;
378 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
379 if (p == NULL)
380 return -1;
381 prof_data = p;
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;
390 return n;
393 int64_t ast_profile(int i, int64_t delta)
395 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
396 return 0;
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>
407 #elif defined(linux)
408 static __inline u_int64_t
409 rdtsc(void)
411 uint64_t rv;
413 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
414 return (rv);
416 #endif
417 #else /* supply a dummy function on other platforms */
418 static __inline u_int64_t
419 rdtsc(void)
421 return 0;
423 #endif
425 int64_t ast_mark(int i, int startstop)
427 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
428 return 0;
429 if (startstop == 1)
430 prof_data->e[i].mark = rdtsc();
431 else {
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(int fd, int argc, char *argv[])
443 int i, min, max;
444 char *search = NULL;
446 if (prof_data == NULL)
447 return 0;
449 min = 0;
450 max = prof_data->entries;
451 if (argc >= 3) { /* specific entries */
452 if (isdigit(argv[2][0])) {
453 min = atoi(argv[2]);
454 if (argc == 4 && strcmp(argv[3], "-"))
455 max = atoi(argv[3]);
456 } else
457 search = argv[2];
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;
468 return 0;
470 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
471 prof_data->entries, prof_data->max_size);
472 for (i = min; i < max; i++) {
473 struct profile_entry *e = &prof_data->e[i];
474 if (!search || strstr(prof_data->e[i].name, search))
475 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
477 (long)e->scale,
478 (long)e->events, (long long)e->value,
479 (long long)(e->events ? e->value / e->events : e->value),
480 e->name);
482 return 0;
485 static char show_version_files_help[] =
486 "Usage: show version files [like <pattern>]\n"
487 " Shows the revision numbers of the files used to build this copy of Asterisk.\n"
488 " Optional regular expression pattern is used to filter the file list.\n";
490 /*! \brief CLI command to list module versions */
491 static int handle_show_version_files(int fd, int argc, char *argv[])
493 #define FORMAT "%-25.25s %-40.40s\n"
494 struct file_version *iterator;
495 regex_t regexbuf;
496 int havepattern = 0;
497 int havename = 0;
498 int count_files = 0;
500 switch (argc) {
501 case 5:
502 if (!strcasecmp(argv[3], "like")) {
503 if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
504 return RESULT_SHOWUSAGE;
505 havepattern = 1;
506 } else
507 return RESULT_SHOWUSAGE;
508 break;
509 case 4:
510 havename = 1;
511 break;
512 case 3:
513 break;
514 default:
515 return RESULT_SHOWUSAGE;
518 ast_cli(fd, FORMAT, "File", "Revision");
519 ast_cli(fd, FORMAT, "----", "--------");
520 AST_LIST_LOCK(&file_versions);
521 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
522 if (havename && strcasecmp(iterator->file, argv[3]))
523 continue;
525 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
526 continue;
528 ast_cli(fd, FORMAT, iterator->file, iterator->version);
529 count_files++;
530 if (havename)
531 break;
533 AST_LIST_UNLOCK(&file_versions);
534 if (!havename) {
535 ast_cli(fd, "%d files listed.\n", count_files);
538 if (havepattern)
539 regfree(&regexbuf);
541 return RESULT_SUCCESS;
542 #undef FORMAT
545 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
547 struct file_version *find;
548 int which = 0;
549 char *ret = NULL;
550 int matchlen = strlen(word);
552 if (pos != 3)
553 return NULL;
555 AST_LIST_LOCK(&file_versions);
556 AST_LIST_TRAVERSE(&file_versions, find, list) {
557 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
558 ret = ast_strdup(find->file);
559 break;
562 AST_LIST_UNLOCK(&file_versions);
564 return ret;
566 #endif /* ! LOW_MEMORY */
568 int ast_register_atexit(void (*func)(void))
570 int res = -1;
571 struct ast_atexit *ae;
572 ast_unregister_atexit(func);
573 AST_LIST_LOCK(&atexits);
574 if ((ae = ast_calloc(1, sizeof(*ae)))) {
575 AST_LIST_INSERT_HEAD(&atexits, ae, list);
576 ae->func = func;
577 res = 0;
579 AST_LIST_UNLOCK(&atexits);
580 return res;
583 void ast_unregister_atexit(void (*func)(void))
585 struct ast_atexit *ae;
586 AST_LIST_LOCK(&atexits);
587 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
588 if (ae->func == func) {
589 AST_LIST_REMOVE_CURRENT(&atexits, list);
590 break;
593 AST_LIST_TRAVERSE_SAFE_END
594 AST_LIST_UNLOCK(&atexits);
597 static int fdprint(int fd, const char *s)
599 return write(fd, s, strlen(s) + 1);
602 /*! \brief NULL handler so we can collect the child exit status */
603 static void null_sig_handler(int signal)
608 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
609 /*! \brief Keep track of how many threads are currently trying to wait*() on
610 * a child process */
611 static unsigned int safe_system_level = 0;
612 static void *safe_system_prev_handler;
614 void ast_replace_sigchld(void)
616 unsigned int level;
618 ast_mutex_lock(&safe_system_lock);
619 level = safe_system_level++;
621 /* only replace the handler if it has not already been done */
622 if (level == 0)
623 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
625 ast_mutex_unlock(&safe_system_lock);
628 void ast_unreplace_sigchld(void)
630 unsigned int level;
632 ast_mutex_lock(&safe_system_lock);
633 level = --safe_system_level;
635 /* only restore the handler if we are the last one */
636 if (level == 0)
637 signal(SIGCHLD, safe_system_prev_handler);
639 ast_mutex_unlock(&safe_system_lock);
642 int ast_safe_system(const char *s)
644 pid_t pid;
645 int x;
646 int res;
647 struct rusage rusage;
648 int status;
650 ast_replace_sigchld();
652 pid = fork();
654 if (pid == 0) {
655 if (ast_opt_high_priority)
656 ast_set_priority(0);
657 /* Close file descriptors and launch system command */
658 for (x = STDERR_FILENO + 1; x < 4096; x++)
659 close(x);
660 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
661 exit(1);
662 } else if (pid > 0) {
663 for(;;) {
664 res = wait4(pid, &status, 0, &rusage);
665 if (res > -1) {
666 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
667 break;
668 } else if (errno != EINTR)
669 break;
671 } else {
672 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
673 res = -1;
676 ast_unreplace_sigchld();
678 return res;
682 * \brief mute or unmute a console from logging
684 void ast_console_toggle_mute(int fd) {
685 int x;
686 for (x = 0;x < AST_MAX_CONNECTS; x++) {
687 if (fd == consoles[x].fd) {
688 if (consoles[x].mute) {
689 consoles[x].mute = 0;
690 ast_cli(fd, "Console is not muted anymore.\n");
691 } else {
692 consoles[x].mute = 1;
693 ast_cli(fd, "Console is muted.\n");
695 return;
698 ast_cli(fd, "Couldn't find remote console.\n");
702 * \brief log the string to all attached console clients
704 static void ast_network_puts_mutable(const char *string)
706 int x;
707 for (x = 0;x < AST_MAX_CONNECTS; x++) {
708 if (consoles[x].mute)
709 continue;
710 if (consoles[x].fd > -1)
711 fdprint(consoles[x].p[1], string);
716 * \brief log the string to the console, and all attached
717 * console clients
719 void ast_console_puts_mutable(const char *string)
721 fputs(string, stdout);
722 fflush(stdout);
723 ast_network_puts_mutable(string);
727 * \brief write the string to all attached console clients
729 static void ast_network_puts(const char *string)
731 int x;
732 for (x=0; x < AST_MAX_CONNECTS; x++) {
733 if (consoles[x].fd > -1)
734 fdprint(consoles[x].p[1], string);
739 * write the string to the console, and all attached
740 * console clients
742 void ast_console_puts(const char *string)
744 fputs(string, stdout);
745 fflush(stdout);
746 ast_network_puts(string);
749 static void network_verboser(const char *s, int pos, int replace, int complete)
750 /* ARGUSED */
752 if (replace) {
753 char *t;
754 if ((t = alloca(strlen(s) + 2))) {
755 sprintf(t, "\r%s", s);
756 if (complete)
757 ast_network_puts_mutable(t);
758 } else {
759 ast_log(LOG_ERROR, "Out of memory\n");
760 ast_network_puts_mutable(s);
762 } else {
763 if (complete)
764 ast_network_puts_mutable(s);
768 static pthread_t lthread;
770 static void *netconsole(void *vconsole)
772 struct console *con = vconsole;
773 char hostname[MAXHOSTNAMELEN] = "";
774 char tmp[512];
775 int res;
776 struct pollfd fds[2];
778 if (gethostname(hostname, sizeof(hostname)-1))
779 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
780 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
781 fdprint(con->fd, tmp);
782 for(;;) {
783 fds[0].fd = con->fd;
784 fds[0].events = POLLIN;
785 fds[0].revents = 0;
786 fds[1].fd = con->p[0];
787 fds[1].events = POLLIN;
788 fds[1].revents = 0;
790 res = poll(fds, 2, -1);
791 if (res < 0) {
792 if (errno != EINTR)
793 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
794 continue;
796 if (fds[0].revents) {
797 res = read(con->fd, tmp, sizeof(tmp));
798 if (res < 1) {
799 break;
801 tmp[res] = 0;
802 ast_cli_command(con->fd, tmp);
804 if (fds[1].revents) {
805 res = read(con->p[0], tmp, sizeof(tmp));
806 if (res < 1) {
807 ast_log(LOG_ERROR, "read returned %d\n", res);
808 break;
810 res = write(con->fd, tmp, res);
811 if (res < 1)
812 break;
815 if (option_verbose > 2)
816 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
817 close(con->fd);
818 close(con->p[0]);
819 close(con->p[1]);
820 con->fd = -1;
822 return NULL;
825 static void *listener(void *unused)
827 struct sockaddr_un sunaddr;
828 int s;
829 socklen_t len;
830 int x;
831 int flags;
832 struct pollfd fds[1];
833 pthread_attr_t attr;
834 pthread_attr_init(&attr);
835 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
836 for (;;) {
837 if (ast_socket < 0)
838 return NULL;
839 fds[0].fd = ast_socket;
840 fds[0].events = POLLIN;
841 s = poll(fds, 1, -1);
842 pthread_testcancel();
843 if (s < 0) {
844 if (errno != EINTR)
845 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
846 continue;
848 len = sizeof(sunaddr);
849 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
850 if (s < 0) {
851 if (errno != EINTR)
852 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
853 } else {
854 for (x = 0; x < AST_MAX_CONNECTS; x++) {
855 if (consoles[x].fd < 0) {
856 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
857 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
858 consoles[x].fd = -1;
859 fdprint(s, "Server failed to create pipe\n");
860 close(s);
861 break;
863 flags = fcntl(consoles[x].p[1], F_GETFL);
864 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
865 consoles[x].fd = s;
866 consoles[x].mute = ast_opt_mute;
867 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
868 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
869 close(consoles[x].p[0]);
870 close(consoles[x].p[1]);
871 consoles[x].fd = -1;
872 fdprint(s, "Server failed to spawn thread\n");
873 close(s);
875 break;
878 if (x >= AST_MAX_CONNECTS) {
879 fdprint(s, "No more connections allowed\n");
880 ast_log(LOG_WARNING, "No more connections allowed\n");
881 close(s);
882 } else if (consoles[x].fd > -1) {
883 if (option_verbose > 2)
884 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
888 return NULL;
891 static int ast_makesocket(void)
893 struct sockaddr_un sunaddr;
894 int res;
895 int x;
896 uid_t uid = -1;
897 gid_t gid = -1;
899 for (x = 0; x < AST_MAX_CONNECTS; x++)
900 consoles[x].fd = -1;
901 unlink(ast_config_AST_SOCKET);
902 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
903 if (ast_socket < 0) {
904 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
905 return -1;
907 memset(&sunaddr, 0, sizeof(sunaddr));
908 sunaddr.sun_family = AF_LOCAL;
909 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
910 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
911 if (res) {
912 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
913 close(ast_socket);
914 ast_socket = -1;
915 return -1;
917 res = listen(ast_socket, 2);
918 if (res < 0) {
919 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
920 close(ast_socket);
921 ast_socket = -1;
922 return -1;
924 ast_register_verbose(network_verboser);
925 ast_pthread_create(&lthread, NULL, listener, NULL);
927 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
928 struct passwd *pw;
929 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
930 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
931 } else {
932 uid = pw->pw_uid;
936 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
937 struct group *grp;
938 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
939 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
940 } else {
941 gid = grp->gr_gid;
945 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
946 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
948 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
949 int p1;
950 mode_t p;
951 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
952 p = p1;
953 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
954 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
957 return 0;
960 static int ast_tryconnect(void)
962 struct sockaddr_un sunaddr;
963 int res;
964 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
965 if (ast_consock < 0) {
966 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
967 return 0;
969 memset(&sunaddr, 0, sizeof(sunaddr));
970 sunaddr.sun_family = AF_LOCAL;
971 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
972 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
973 if (res) {
974 close(ast_consock);
975 ast_consock = -1;
976 return 0;
977 } else
978 return 1;
981 /*! \brief Urgent handler
983 Called by soft_hangup to interrupt the poll, read, or other
984 system call. We don't actually need to do anything though.
985 Remember: Cannot EVER ast_log from within a signal handler
987 static void urg_handler(int num)
989 signal(num, urg_handler);
990 return;
993 static void hup_handler(int num)
995 if (option_verbose > 1)
996 printf("Received HUP signal -- Reloading configs\n");
997 if (restartnow)
998 execvp(_argv[0], _argv);
999 /* XXX This could deadlock XXX */
1000 ast_module_reload(NULL);
1001 signal(num, hup_handler);
1004 static void child_handler(int sig)
1006 /* Must not ever ast_log or ast_verbose within signal handler */
1007 int n, status;
1010 * Reap all dead children -- not just one
1012 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1014 if (n == 0 && option_debug)
1015 printf("Huh? Child handler, but nobody there?\n");
1016 signal(sig, child_handler);
1019 /*! \brief Set an X-term or screen title */
1020 static void set_title(char *text)
1022 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1023 fprintf(stdout, "\033]2;%s\007", text);
1026 static void set_icon(char *text)
1028 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1029 fprintf(stdout, "\033]1;%s\007", text);
1032 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1033 else. If your PBX has heavy activity on it, this is a good thing. */
1034 int ast_set_priority(int pri)
1036 struct sched_param sched;
1037 memset(&sched, 0, sizeof(sched));
1038 #ifdef __linux__
1039 if (pri) {
1040 sched.sched_priority = 10;
1041 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1042 ast_log(LOG_WARNING, "Unable to set high priority\n");
1043 return -1;
1044 } else
1045 if (option_verbose)
1046 ast_verbose("Set to realtime thread\n");
1047 } else {
1048 sched.sched_priority = 0;
1049 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
1050 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1051 return -1;
1054 #else
1055 if (pri) {
1056 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1057 ast_log(LOG_WARNING, "Unable to set high priority\n");
1058 return -1;
1059 } else
1060 if (option_verbose)
1061 ast_verbose("Set to high priority\n");
1062 } else {
1063 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1064 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1065 return -1;
1068 #endif
1069 return 0;
1072 static void ast_run_atexits(void)
1074 struct ast_atexit *ae;
1075 AST_LIST_LOCK(&atexits);
1076 AST_LIST_TRAVERSE(&atexits, ae, list) {
1077 if (ae->func)
1078 ae->func();
1080 AST_LIST_UNLOCK(&atexits);
1083 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1085 char filename[80] = "";
1086 time_t s,e;
1087 int x;
1088 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1089 ast_cdr_engine_term();
1090 if (safeshutdown) {
1091 shuttingdown = 1;
1092 if (!nice) {
1093 /* Begin shutdown routine, hanging up active channels */
1094 ast_begin_shutdown(1);
1095 if (option_verbose && ast_opt_console)
1096 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1097 time(&s);
1098 for (;;) {
1099 time(&e);
1100 /* Wait up to 15 seconds for all channels to go away */
1101 if ((e - s) > 15)
1102 break;
1103 if (!ast_active_channels())
1104 break;
1105 if (!shuttingdown)
1106 break;
1107 /* Sleep 1/10 of a second */
1108 usleep(100000);
1110 } else {
1111 if (nice < 2)
1112 ast_begin_shutdown(0);
1113 if (option_verbose && ast_opt_console)
1114 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1115 for (;;) {
1116 if (!ast_active_channels())
1117 break;
1118 if (!shuttingdown)
1119 break;
1120 sleep(1);
1124 if (!shuttingdown) {
1125 if (option_verbose && ast_opt_console)
1126 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1127 return;
1130 if (ast_opt_console || ast_opt_remote) {
1131 if (getenv("HOME"))
1132 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1133 if (!ast_strlen_zero(filename))
1134 ast_el_write_history(filename);
1135 if (el != NULL)
1136 el_end(el);
1137 if (el_hist != NULL)
1138 history_end(el_hist);
1140 if (option_verbose)
1141 ast_verbose("Executing last minute cleanups\n");
1142 ast_run_atexits();
1143 /* Called on exit */
1144 if (option_verbose && ast_opt_console)
1145 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1146 else if (option_debug)
1147 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1148 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1149 if (ast_socket > -1) {
1150 pthread_cancel(lthread);
1151 close(ast_socket);
1152 ast_socket = -1;
1153 unlink(ast_config_AST_SOCKET);
1155 if (ast_consock > -1)
1156 close(ast_consock);
1157 if (!ast_opt_remote)
1158 unlink(ast_config_AST_PID);
1159 printf(term_quit());
1160 if (restart) {
1161 if (option_verbose || ast_opt_console)
1162 ast_verbose("Preparing for Asterisk restart...\n");
1163 /* Mark all FD's for closing on exec */
1164 for (x=3; x < 32768; x++) {
1165 fcntl(x, F_SETFD, FD_CLOEXEC);
1167 if (option_verbose || ast_opt_console)
1168 ast_verbose("Restarting Asterisk NOW...\n");
1169 restartnow = 1;
1171 /* close logger */
1172 close_logger();
1174 /* If there is a consolethread running send it a SIGHUP
1175 so it can execvp, otherwise we can do it ourselves */
1176 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1177 pthread_kill(consolethread, SIGHUP);
1178 /* Give the signal handler some time to complete */
1179 sleep(2);
1180 } else
1181 execvp(_argv[0], _argv);
1183 } else {
1184 /* close logger */
1185 close_logger();
1187 exit(0);
1190 static void __quit_handler(int num)
1192 quit_handler(num, 0, 1, 0);
1195 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1197 const char *c;
1198 if (!strncmp(s, cmp, strlen(cmp))) {
1199 c = s + strlen(cmp);
1200 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1201 return c;
1203 return NULL;
1206 static void console_verboser(const char *s, int pos, int replace, int complete)
1208 char tmp[80];
1209 const char *c = NULL;
1210 /* Return to the beginning of the line */
1211 if (!pos) {
1212 fprintf(stdout, "\r");
1213 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1214 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1215 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1216 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
1217 fputs(tmp, stdout);
1219 if (c)
1220 fputs(c + pos,stdout);
1221 else
1222 fputs(s + pos,stdout);
1223 fflush(stdout);
1224 if (complete) {
1225 /* Wake up a poll()ing console */
1226 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1227 pthread_kill(consolethread, SIGURG);
1231 static int ast_all_zeros(char *s)
1233 while (*s) {
1234 if (*s > 32)
1235 return 0;
1236 s++;
1238 return 1;
1241 static void consolehandler(char *s)
1243 printf(term_end());
1244 fflush(stdout);
1246 /* Called when readline data is available */
1247 if (!ast_all_zeros(s))
1248 ast_el_add_history(s);
1249 /* The real handler for bang */
1250 if (s[0] == '!') {
1251 if (s[1])
1252 ast_safe_system(s+1);
1253 else
1254 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1255 } else
1256 ast_cli_command(STDOUT_FILENO, s);
1259 static int remoteconsolehandler(char *s)
1261 int ret = 0;
1263 /* Called when readline data is available */
1264 if (!ast_all_zeros(s))
1265 ast_el_add_history(s);
1266 /* The real handler for bang */
1267 if (s[0] == '!') {
1268 if (s[1])
1269 ast_safe_system(s+1);
1270 else
1271 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1272 ret = 1;
1274 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1275 (s[4] == '\0' || isspace(s[4]))) {
1276 quit_handler(0, 0, 0, 0);
1277 ret = 1;
1280 return ret;
1283 static char abort_halt_help[] =
1284 "Usage: abort shutdown\n"
1285 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1286 " call operations.\n";
1288 static char shutdown_now_help[] =
1289 "Usage: stop now\n"
1290 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1292 static char shutdown_gracefully_help[] =
1293 "Usage: stop gracefully\n"
1294 " Causes Asterisk to not accept new calls, and exit when all\n"
1295 " active calls have terminated normally.\n";
1297 static char shutdown_when_convenient_help[] =
1298 "Usage: stop when convenient\n"
1299 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1301 static char restart_now_help[] =
1302 "Usage: restart now\n"
1303 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1304 " restart.\n";
1306 static char restart_gracefully_help[] =
1307 "Usage: restart gracefully\n"
1308 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1309 " restart when all active calls have ended.\n";
1311 static char restart_when_convenient_help[] =
1312 "Usage: restart when convenient\n"
1313 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1315 static char bang_help[] =
1316 "Usage: !<command>\n"
1317 " Executes a given shell command\n";
1319 static char show_warranty_help[] =
1320 "Usage: show warranty\n"
1321 " Shows the warranty (if any) for this copy of Asterisk.\n";
1323 static char show_license_help[] =
1324 "Usage: show license\n"
1325 " Shows the license(s) for this copy of Asterisk.\n";
1327 static char version_help[] =
1328 "Usage: show version\n"
1329 " Shows Asterisk version information.\n";
1331 static int handle_version(int fd, int argc, char *argv[])
1333 if (argc != 2)
1334 return RESULT_SHOWUSAGE;
1335 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1336 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1337 ast_build_machine, ast_build_os, ast_build_date);
1338 return RESULT_SUCCESS;
1341 #if 0
1342 static int handle_quit(int fd, int argc, char *argv[])
1344 if (argc != 1)
1345 return RESULT_SHOWUSAGE;
1346 quit_handler(0, 0, 1, 0);
1347 return RESULT_SUCCESS;
1349 #endif
1351 static int handle_shutdown_now(int fd, int argc, char *argv[])
1353 if (argc != 2)
1354 return RESULT_SHOWUSAGE;
1355 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1356 return RESULT_SUCCESS;
1359 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1361 if (argc != 2)
1362 return RESULT_SHOWUSAGE;
1363 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1364 return RESULT_SUCCESS;
1367 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1369 if (argc != 3)
1370 return RESULT_SHOWUSAGE;
1371 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1372 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1373 return RESULT_SUCCESS;
1376 static int handle_restart_now(int fd, int argc, char *argv[])
1378 if (argc != 2)
1379 return RESULT_SHOWUSAGE;
1380 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1381 return RESULT_SUCCESS;
1384 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1386 if (argc != 2)
1387 return RESULT_SHOWUSAGE;
1388 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1389 return RESULT_SUCCESS;
1392 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1394 if (argc != 3)
1395 return RESULT_SHOWUSAGE;
1396 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1397 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1398 return RESULT_SUCCESS;
1401 static int handle_abort_halt(int fd, int argc, char *argv[])
1403 if (argc != 2)
1404 return RESULT_SHOWUSAGE;
1405 ast_cancel_shutdown();
1406 shuttingdown = 0;
1407 return RESULT_SUCCESS;
1410 static int handle_bang(int fd, int argc, char *argv[])
1412 return RESULT_SUCCESS;
1414 static const char *warranty_lines[] = {
1415 "\n",
1416 " NO WARRANTY\n",
1417 "\n",
1418 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1419 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1420 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1421 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1422 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1423 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1424 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1425 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1426 "REPAIR OR CORRECTION.\n",
1427 "\n",
1428 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1429 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1430 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1431 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1432 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1433 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1434 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1435 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1436 "POSSIBILITY OF SUCH DAMAGES.\n",
1439 static int show_warranty(int fd, int argc, char *argv[])
1441 int x;
1443 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1444 ast_cli(fd, (char *) warranty_lines[x]);
1446 return RESULT_SUCCESS;
1449 static const char *license_lines[] = {
1450 "\n",
1451 "This program is free software; you can redistribute it and/or modify\n",
1452 "it under the terms of the GNU General Public License version 2 as\n",
1453 "published by the Free Software Foundation.\n",
1454 "\n",
1455 "This program also contains components licensed under other licenses.\n",
1456 "They include:\n",
1457 "\n",
1458 "This program is distributed in the hope that it will be useful,\n",
1459 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1460 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1461 "GNU General Public License for more details.\n",
1462 "\n",
1463 "You should have received a copy of the GNU General Public License\n",
1464 "along with this program; if not, write to the Free Software\n",
1465 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1468 static int show_license(int fd, int argc, char *argv[])
1470 int x;
1472 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1473 ast_cli(fd, (char *) license_lines[x]);
1475 return RESULT_SUCCESS;
1478 #define ASTERISK_PROMPT "*CLI> "
1480 #define ASTERISK_PROMPT2 "%s*CLI> "
1482 static struct ast_cli_entry core_cli[] = {
1483 { { "abort", "halt", NULL }, handle_abort_halt,
1484 "Cancel a running halt", abort_halt_help },
1485 { { "stop", "now", NULL }, handle_shutdown_now,
1486 "Shut down Asterisk immediately", shutdown_now_help },
1487 { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1488 "Gracefully shut down Asterisk", shutdown_gracefully_help },
1489 { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1490 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1491 { { "restart", "now", NULL }, handle_restart_now,
1492 "Restart Asterisk immediately", restart_now_help },
1493 { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1494 "Restart Asterisk gracefully", restart_gracefully_help },
1495 { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1496 "Restart Asterisk at empty call volume", restart_when_convenient_help },
1497 { { "show", "warranty", NULL }, show_warranty,
1498 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
1499 { { "show", "license", NULL }, show_license,
1500 "Show the license(s) for this copy of Asterisk", show_license_help },
1501 { { "show", "version", NULL }, handle_version,
1502 "Display version info", version_help },
1503 { { "!", NULL }, handle_bang,
1504 "Execute a shell command", bang_help },
1505 #if !defined(LOW_MEMORY)
1506 { { "show", "version", "files", NULL }, handle_show_version_files,
1507 "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1508 { { "show", "threads", NULL }, handle_show_threads,
1509 "Show running threads", show_threads_help, NULL },
1510 { { "show", "profile", NULL }, handle_show_profile,
1511 "Show profiling info"},
1512 { { "clear", "profile", NULL }, handle_show_profile,
1513 "Clear profiling info"},
1514 #endif /* ! LOW_MEMORY */
1517 static int ast_el_read_char(EditLine *el, char *cp)
1519 int num_read = 0;
1520 int lastpos = 0;
1521 struct pollfd fds[2];
1522 int res;
1523 int max;
1524 char buf[512];
1526 for (;;) {
1527 max = 1;
1528 fds[0].fd = ast_consock;
1529 fds[0].events = POLLIN;
1530 if (!ast_opt_exec) {
1531 fds[1].fd = STDIN_FILENO;
1532 fds[1].events = POLLIN;
1533 max++;
1535 res = poll(fds, max, -1);
1536 if (res < 0) {
1537 if (errno == EINTR)
1538 continue;
1539 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1540 break;
1543 if (!ast_opt_exec && fds[1].revents) {
1544 num_read = read(STDIN_FILENO, cp, 1);
1545 if (num_read < 1) {
1546 break;
1547 } else
1548 return (num_read);
1550 if (fds[0].revents) {
1551 res = read(ast_consock, buf, sizeof(buf) - 1);
1552 /* if the remote side disappears exit */
1553 if (res < 1) {
1554 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1555 if (!ast_opt_reconnect) {
1556 quit_handler(0, 0, 0, 0);
1557 } else {
1558 int tries;
1559 int reconnects_per_second = 20;
1560 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1561 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1562 if (ast_tryconnect()) {
1563 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1564 printf(term_quit());
1565 WELCOME_MESSAGE;
1566 break;
1567 } else {
1568 usleep(1000000 / reconnects_per_second);
1571 if (tries >= 30 * reconnects_per_second) {
1572 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1573 quit_handler(0, 0, 0, 0);
1578 buf[res] = '\0';
1580 if (!ast_opt_exec && !lastpos)
1581 write(STDOUT_FILENO, "\r", 1);
1582 write(STDOUT_FILENO, buf, res);
1583 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1584 *cp = CC_REFRESH;
1585 return(1);
1586 } else {
1587 lastpos = 1;
1592 *cp = '\0';
1593 return (0);
1596 static char *cli_prompt(EditLine *el)
1598 static char prompt[200];
1599 char *pfmt;
1600 int color_used = 0;
1601 char term_code[20];
1603 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1604 char *t = pfmt, *p = prompt;
1605 memset(prompt, 0, sizeof(prompt));
1606 while (*t != '\0' && *p < sizeof(prompt)) {
1607 if (*t == '%') {
1608 char hostname[MAXHOSTNAMELEN]="";
1609 int i;
1610 time_t ts;
1611 struct tm tm;
1612 #ifdef linux
1613 FILE *LOADAVG;
1614 #endif
1615 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1617 t++;
1618 switch (*t) {
1619 case 'C': /* color */
1620 t++;
1621 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1622 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1623 t += i - 1;
1624 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1625 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1626 t += i - 1;
1629 /* If the color has been reset correctly, then there's no need to reset it later */
1630 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1631 color_used = 0;
1632 } else {
1633 color_used = 1;
1635 break;
1636 case 'd': /* date */
1637 memset(&tm, 0, sizeof(tm));
1638 time(&ts);
1639 if (localtime_r(&ts, &tm)) {
1640 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1642 break;
1643 case 'h': /* hostname */
1644 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1645 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1646 } else {
1647 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1649 break;
1650 case 'H': /* short hostname */
1651 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1652 for (i = 0; i < sizeof(hostname); i++) {
1653 if (hostname[i] == '.') {
1654 hostname[i] = '\0';
1655 break;
1658 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1659 } else {
1660 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1662 break;
1663 #ifdef linux
1664 case 'l': /* load avg */
1665 t++;
1666 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1667 float avg1, avg2, avg3;
1668 int actproc, totproc, npid, which;
1669 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1670 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1671 if (sscanf(t, "%d", &which) == 1) {
1672 switch (which) {
1673 case 1:
1674 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1675 break;
1676 case 2:
1677 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1678 break;
1679 case 3:
1680 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1681 break;
1682 case 4:
1683 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1684 break;
1685 case 5:
1686 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1687 break;
1691 break;
1692 #endif
1693 case 's': /* Asterisk system name (from asterisk.conf) */
1694 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1695 break;
1696 case 't': /* time */
1697 memset(&tm, 0, sizeof(tm));
1698 time(&ts);
1699 if (localtime_r(&ts, &tm)) {
1700 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1702 break;
1703 case '#': /* process console or remote? */
1704 if (!ast_opt_remote) {
1705 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1706 } else {
1707 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1709 break;
1710 case '%': /* literal % */
1711 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1712 break;
1713 case '\0': /* % is last character - prevent bug */
1714 t--;
1715 break;
1717 while (*p != '\0') {
1718 p++;
1720 t++;
1721 } else {
1722 *p = *t;
1723 p++;
1724 t++;
1727 if (color_used) {
1728 /* Force colors back to normal at end */
1729 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1730 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1731 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1732 } else {
1733 strncat(p, term_code, sizeof(term_code));
1736 } else if (remotehostname)
1737 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1738 else
1739 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1741 return(prompt);
1744 static char **ast_el_strtoarr(char *buf)
1746 char **match_list = NULL, *retstr;
1747 size_t match_list_len;
1748 int matches = 0;
1750 match_list_len = 1;
1751 while ( (retstr = strsep(&buf, " ")) != NULL) {
1753 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1754 break;
1755 if (matches + 1 >= match_list_len) {
1756 match_list_len <<= 1;
1757 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1758 /* TODO: Handle memory allocation failure */
1762 match_list[matches++] = strdup(retstr);
1765 if (!match_list)
1766 return (char **) NULL;
1768 if (matches >= match_list_len) {
1769 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1770 /* TODO: Handle memory allocation failure */
1774 match_list[matches] = (char *) NULL;
1776 return match_list;
1779 static int ast_el_sort_compare(const void *i1, const void *i2)
1781 char *s1, *s2;
1783 s1 = ((char **)i1)[0];
1784 s2 = ((char **)i2)[0];
1786 return strcasecmp(s1, s2);
1789 static int ast_cli_display_match_list(char **matches, int len, int max)
1791 int i, idx, limit, count;
1792 int screenwidth = 0;
1793 int numoutput = 0, numoutputline = 0;
1795 screenwidth = ast_get_termcols(STDOUT_FILENO);
1797 /* find out how many entries can be put on one line, with two spaces between strings */
1798 limit = screenwidth / (max + 2);
1799 if (limit == 0)
1800 limit = 1;
1802 /* how many lines of output */
1803 count = len / limit;
1804 if (count * limit < len)
1805 count++;
1807 idx = 1;
1809 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1811 for (; count > 0; count--) {
1812 numoutputline = 0;
1813 for (i=0; i < limit && matches[idx]; i++, idx++) {
1815 /* Don't print dupes */
1816 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1817 i--;
1818 free(matches[idx]);
1819 matches[idx] = NULL;
1820 continue;
1823 numoutput++;
1824 numoutputline++;
1825 fprintf(stdout, "%-*s ", max, matches[idx]);
1826 free(matches[idx]);
1827 matches[idx] = NULL;
1829 if (numoutputline > 0)
1830 fprintf(stdout, "\n");
1833 return numoutput;
1837 static char *cli_complete(EditLine *el, int ch)
1839 int len = 0;
1840 char *ptr;
1841 int nummatches = 0;
1842 char **matches;
1843 int retval = CC_ERROR;
1844 char buf[2048];
1845 int res;
1847 LineInfo *lf = (LineInfo *)el_line(el);
1849 *(char *)lf->cursor = '\0';
1850 ptr = (char *)lf->cursor;
1851 if (ptr) {
1852 while (ptr > lf->buffer) {
1853 if (isspace(*ptr)) {
1854 ptr++;
1855 break;
1857 ptr--;
1861 len = lf->cursor - ptr;
1863 if (ast_opt_remote) {
1864 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1865 fdprint(ast_consock, buf);
1866 res = read(ast_consock, buf, sizeof(buf));
1867 buf[res] = '\0';
1868 nummatches = atoi(buf);
1870 if (nummatches > 0) {
1871 char *mbuf;
1872 int mlen = 0, maxmbuf = 2048;
1873 /* Start with a 2048 byte buffer */
1874 if (!(mbuf = ast_malloc(maxmbuf)))
1875 return (char *)(CC_ERROR);
1876 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1877 fdprint(ast_consock, buf);
1878 res = 0;
1879 mbuf[0] = '\0';
1880 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1881 if (mlen + 1024 > maxmbuf) {
1882 /* Every step increment buffer 1024 bytes */
1883 maxmbuf += 1024;
1884 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1885 return (char *)(CC_ERROR);
1887 /* Only read 1024 bytes at a time */
1888 res = read(ast_consock, mbuf + mlen, 1024);
1889 if (res > 0)
1890 mlen += res;
1892 mbuf[mlen] = '\0';
1894 matches = ast_el_strtoarr(mbuf);
1895 free(mbuf);
1896 } else
1897 matches = (char **) NULL;
1898 } else {
1899 char **p, *oldbuf=NULL;
1900 nummatches = 0;
1901 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1902 for (p = matches; p && *p; p++) {
1903 if (!oldbuf || strcmp(*p,oldbuf))
1904 nummatches++;
1905 oldbuf = *p;
1909 if (matches) {
1910 int i;
1911 int matches_num, maxlen, match_len;
1913 if (matches[0][0] != '\0') {
1914 el_deletestr(el, (int) len);
1915 el_insertstr(el, matches[0]);
1916 retval = CC_REFRESH;
1919 if (nummatches == 1) {
1920 /* Found an exact match */
1921 el_insertstr(el, " ");
1922 retval = CC_REFRESH;
1923 } else {
1924 /* Must be more than one match */
1925 for (i=1, maxlen=0; matches[i]; i++) {
1926 match_len = strlen(matches[i]);
1927 if (match_len > maxlen)
1928 maxlen = match_len;
1930 matches_num = i - 1;
1931 if (matches_num >1) {
1932 fprintf(stdout, "\n");
1933 ast_cli_display_match_list(matches, nummatches, maxlen);
1934 retval = CC_REDISPLAY;
1935 } else {
1936 el_insertstr(el," ");
1937 retval = CC_REFRESH;
1940 free(matches);
1943 return (char *)(long)retval;
1946 static int ast_el_initialize(void)
1948 HistEvent ev;
1949 char *editor = getenv("AST_EDITOR");
1951 if (el != NULL)
1952 el_end(el);
1953 if (el_hist != NULL)
1954 history_end(el_hist);
1956 el = el_init("asterisk", stdin, stdout, stderr);
1957 el_set(el, EL_PROMPT, cli_prompt);
1959 el_set(el, EL_EDITMODE, 1);
1960 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1961 el_hist = history_init();
1962 if (!el || !el_hist)
1963 return -1;
1965 /* setup history with 100 entries */
1966 history(el_hist, &ev, H_SETSIZE, 100);
1968 el_set(el, EL_HIST, history, el_hist);
1970 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1971 /* Bind <tab> to command completion */
1972 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1973 /* Bind ? to command completion */
1974 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1975 /* Bind ^D to redisplay */
1976 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1978 return 0;
1981 static int ast_el_add_history(char *buf)
1983 HistEvent ev;
1985 if (el_hist == NULL || el == NULL)
1986 ast_el_initialize();
1987 if (strlen(buf) > 256)
1988 return 0;
1989 return (history(el_hist, &ev, H_ENTER, buf));
1992 static int ast_el_write_history(char *filename)
1994 HistEvent ev;
1996 if (el_hist == NULL || el == NULL)
1997 ast_el_initialize();
1999 return (history(el_hist, &ev, H_SAVE, filename));
2002 static int ast_el_read_history(char *filename)
2004 char buf[256];
2005 FILE *f;
2006 int ret = -1;
2008 if (el_hist == NULL || el == NULL)
2009 ast_el_initialize();
2011 if ((f = fopen(filename, "r")) == NULL)
2012 return ret;
2014 while (!feof(f)) {
2015 fgets(buf, sizeof(buf), f);
2016 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2017 continue;
2018 if (ast_all_zeros(buf))
2019 continue;
2020 if ((ret = ast_el_add_history(buf)) == -1)
2021 break;
2023 fclose(f);
2025 return ret;
2028 static void ast_remotecontrol(char * data)
2030 char buf[80];
2031 int res;
2032 char filename[80] = "";
2033 char *hostname;
2034 char *cpid;
2035 char *version;
2036 int pid;
2037 char tmp[80];
2038 char *stringp = NULL;
2040 char *ebuf;
2041 int num = 0;
2043 read(ast_consock, buf, sizeof(buf));
2044 if (data)
2045 write(ast_consock, data, strlen(data) + 1);
2046 stringp = buf;
2047 hostname = strsep(&stringp, "/");
2048 cpid = strsep(&stringp, "/");
2049 version = strsep(&stringp, "\n");
2050 if (!version)
2051 version = "<Version Unknown>";
2052 stringp = hostname;
2053 strsep(&stringp, ".");
2054 if (cpid)
2055 pid = atoi(cpid);
2056 else
2057 pid = -1;
2058 snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
2059 fdprint(ast_consock, tmp);
2060 snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
2061 fdprint(ast_consock, tmp);
2062 if (ast_opt_mute) {
2063 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2064 fdprint(ast_consock, tmp);
2066 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2067 remotehostname = hostname;
2068 if (getenv("HOME"))
2069 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2070 if (el_hist == NULL || el == NULL)
2071 ast_el_initialize();
2073 el_set(el, EL_GETCFN, ast_el_read_char);
2075 if (!ast_strlen_zero(filename))
2076 ast_el_read_history(filename);
2078 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2079 char tempchar;
2080 struct pollfd fds;
2081 fds.fd = ast_consock;
2082 fds.events = POLLIN;
2083 fds.revents = 0;
2084 while (poll(&fds, 1, 100) > 0)
2085 ast_el_read_char(el, &tempchar);
2086 return;
2088 for (;;) {
2089 ebuf = (char *)el_gets(el, &num);
2091 if (!ast_strlen_zero(ebuf)) {
2092 if (ebuf[strlen(ebuf)-1] == '\n')
2093 ebuf[strlen(ebuf)-1] = '\0';
2094 if (!remoteconsolehandler(ebuf)) {
2095 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2096 if (res < 1) {
2097 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2098 break;
2103 printf("\nDisconnected from Asterisk server\n");
2106 static int show_version(void)
2108 printf("Asterisk " ASTERISK_VERSION "\n");
2109 return 0;
2112 static int show_cli_help(void) {
2113 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2114 printf("Usage: asterisk [OPTIONS]\n");
2115 printf("Valid Options:\n");
2116 printf(" -V Display version number and exit\n");
2117 printf(" -C <configfile> Use an alternate configuration file\n");
2118 printf(" -G <group> Run as a group other than the caller\n");
2119 printf(" -U <user> Run as a user other than the caller\n");
2120 printf(" -c Provide console CLI\n");
2121 printf(" -d Enable extra debugging\n");
2122 printf(" -f Do not fork\n");
2123 printf(" -g Dump core in case of a crash\n");
2124 printf(" -h This help screen\n");
2125 printf(" -i Initialize crypto keys at startup\n");
2126 printf(" -I Enable internal timing if Zaptel timer is available\n");
2127 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2128 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2129 printf(" -m Mute the console from debugging and verbose output\n");
2130 printf(" -n Disable console colorization\n");
2131 printf(" -p Run as pseudo-realtime thread\n");
2132 printf(" -q Quiet mode (suppress output)\n");
2133 printf(" -r Connect to Asterisk on this machine\n");
2134 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2135 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2136 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2137 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2138 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2139 printf("\n");
2140 return 0;
2143 static void ast_readconfig(void)
2145 struct ast_config *cfg;
2146 struct ast_variable *v;
2147 char *config = AST_CONFIG_FILE;
2149 if (ast_opt_override_config) {
2150 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2151 if (!cfg)
2152 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2153 } else {
2154 cfg = ast_config_load(config);
2157 /* init with buildtime config */
2158 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2159 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2160 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2161 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2162 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2163 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2164 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2165 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2166 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2167 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2168 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2169 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2170 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2172 /* no asterisk.conf? no problem, use buildtime config! */
2173 if (!cfg) {
2174 return;
2177 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2178 if (!strcasecmp(v->name, "astctlpermissions")) {
2179 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2180 } else if (!strcasecmp(v->name, "astctlowner")) {
2181 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2182 } else if (!strcasecmp(v->name, "astctlgroup")) {
2183 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2184 } else if (!strcasecmp(v->name, "astctl")) {
2185 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2189 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2190 if (!strcasecmp(v->name, "astetcdir")) {
2191 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2192 } else if (!strcasecmp(v->name, "astspooldir")) {
2193 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2194 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2195 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2196 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2197 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2198 } else if (!strcasecmp(v->name, "astdatadir")) {
2199 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2200 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2201 } else if (!strcasecmp(v->name, "astlogdir")) {
2202 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2203 } else if (!strcasecmp(v->name, "astagidir")) {
2204 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2205 } else if (!strcasecmp(v->name, "astrundir")) {
2206 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2207 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2208 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2209 } else if (!strcasecmp(v->name, "astmoddir")) {
2210 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2214 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2215 /* verbose level (-v at startup) */
2216 if (!strcasecmp(v->name, "verbose")) {
2217 option_verbose = atoi(v->value);
2218 /* whether or not to force timestamping. (-T at startup) */
2219 } else if (!strcasecmp(v->name, "timestamp")) {
2220 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2221 /* whether or not to support #exec in config files */
2222 } else if (!strcasecmp(v->name, "execincludes")) {
2223 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2224 /* debug level (-d at startup) */
2225 } else if (!strcasecmp(v->name, "debug")) {
2226 option_debug = 0;
2227 if (sscanf(v->value, "%d", &option_debug) != 1) {
2228 option_debug = ast_true(v->value);
2230 /* Disable forking (-f at startup) */
2231 } else if (!strcasecmp(v->name, "nofork")) {
2232 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2233 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2234 } else if (!strcasecmp(v->name, "alwaysfork")) {
2235 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2236 /* Run quietly (-q at startup ) */
2237 } else if (!strcasecmp(v->name, "quiet")) {
2238 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2239 /* Run as console (-c at startup, implies nofork) */
2240 } else if (!strcasecmp(v->name, "console")) {
2241 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2242 /* Run with high priority if the O/S permits (-p at startup) */
2243 } else if (!strcasecmp(v->name, "highpriority")) {
2244 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2245 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2246 } else if (!strcasecmp(v->name, "initcrypto")) {
2247 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2248 /* Disable ANSI colors for console (-c at startup) */
2249 } else if (!strcasecmp(v->name, "nocolor")) {
2250 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2251 /* Disable some usage warnings for picky people :p */
2252 } else if (!strcasecmp(v->name, "dontwarn")) {
2253 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2254 /* Dump core in case of crash (-g) */
2255 } else if (!strcasecmp(v->name, "dumpcore")) {
2256 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2257 /* Cache recorded sound files to another directory during recording */
2258 } else if (!strcasecmp(v->name, "cache_record_files")) {
2259 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2260 /* Specify cache directory */
2261 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2262 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2263 /* Build transcode paths via SLINEAR, instead of directly */
2264 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2265 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2266 /* Transmit SLINEAR silence while a channel is being recorded */
2267 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2268 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2269 /* Enable internal timing */
2270 } else if (!strcasecmp(v->name, "internal_timing")) {
2271 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2272 } else if (!strcasecmp(v->name, "maxcalls")) {
2273 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2274 option_maxcalls = 0;
2276 } else if (!strcasecmp(v->name, "maxload")) {
2277 double test[1];
2279 if (getloadavg(test, 1) == -1) {
2280 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2281 option_maxload = 0.0;
2282 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2283 option_maxload = 0.0;
2285 /* What user to run as */
2286 } else if (!strcasecmp(v->name, "runuser")) {
2287 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2288 /* What group to run as */
2289 } else if (!strcasecmp(v->name, "rungroup")) {
2290 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2291 } else if (!strcasecmp(v->name, "systemname")) {
2292 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2293 } else if (!strcasecmp(v->name, "languageprefix")) {
2294 ast_language_is_prefix = ast_true(v->value);
2297 ast_config_destroy(cfg);
2300 int main(int argc, char *argv[])
2302 int c;
2303 char filename[80] = "";
2304 char hostname[MAXHOSTNAMELEN] = "";
2305 char tmp[80];
2306 char * xarg = NULL;
2307 int x;
2308 FILE *f;
2309 sigset_t sigs;
2310 int num;
2311 int is_child_of_nonroot = 0;
2312 char *buf;
2313 char *runuser = NULL, *rungroup = NULL;
2315 /* Remember original args for restart */
2316 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2317 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2318 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2320 for (x=0; x<argc; x++)
2321 _argv[x] = argv[x];
2322 _argv[x] = NULL;
2324 /* if the progname is rasterisk consider it a remote console */
2325 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2326 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2328 if (gethostname(hostname, sizeof(hostname)-1))
2329 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2330 ast_mainpid = getpid();
2331 ast_ulaw_init();
2332 ast_alaw_init();
2333 callerid_init();
2334 ast_builtins_init();
2335 ast_utils_init();
2336 tdd_init();
2337 /* When Asterisk restarts after it has dropped the root privileges,
2338 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2340 if (getenv("ASTERISK_ALREADY_NONROOT"))
2341 is_child_of_nonroot=1;
2342 if (getenv("HOME"))
2343 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2344 /* Check for options */
2345 while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2346 switch (c) {
2347 case 'F':
2348 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2349 break;
2350 case 'd':
2351 option_debug++;
2352 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2353 break;
2354 case 'c':
2355 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2356 break;
2357 case 'f':
2358 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2359 break;
2360 case 'n':
2361 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2362 break;
2363 case 'r':
2364 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2365 break;
2366 case 'R':
2367 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2368 break;
2369 case 'p':
2370 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2371 break;
2372 case 'v':
2373 option_verbose++;
2374 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2375 break;
2376 case 'm':
2377 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2378 break;
2379 case 'M':
2380 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2381 option_maxcalls = 0;
2382 break;
2383 case 'L':
2384 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2385 option_maxload = 0.0;
2386 break;
2387 case 'q':
2388 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2389 break;
2390 case 't':
2391 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2392 break;
2393 case 'T':
2394 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2395 break;
2396 case 'x':
2397 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2398 xarg = optarg;
2399 break;
2400 case 'C':
2401 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2402 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2403 break;
2404 case 'I':
2405 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2406 break;
2407 case 'i':
2408 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2409 break;
2410 case 'g':
2411 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2412 break;
2413 case 'h':
2414 show_cli_help();
2415 exit(0);
2416 case 'V':
2417 show_version();
2418 exit(0);
2419 case 'U':
2420 runuser = optarg;
2421 break;
2422 case 'G':
2423 rungroup = optarg;
2424 break;
2425 case '?':
2426 exit(1);
2430 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2431 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2432 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2435 /* For remote connections, change the name of the remote connection.
2436 * We do this for the benefit of init scripts (which need to know if/when
2437 * the main asterisk process has died yet). */
2438 if (ast_opt_remote) {
2439 strcpy(argv[0], "rasterisk");
2440 for (x = 1; x < argc; x++) {
2441 argv[x] = argv[0] + 10;
2445 if (ast_opt_console && !option_verbose)
2446 ast_verbose("[ Reading Master Configuration ]");
2447 ast_readconfig();
2449 if (ast_opt_dump_core) {
2450 struct rlimit l;
2451 memset(&l, 0, sizeof(l));
2452 l.rlim_cur = RLIM_INFINITY;
2453 l.rlim_max = RLIM_INFINITY;
2454 if (setrlimit(RLIMIT_CORE, &l)) {
2455 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2459 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2460 rungroup = ast_config_AST_RUN_GROUP;
2461 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2462 runuser = ast_config_AST_RUN_USER;
2464 #ifndef __CYGWIN__
2466 if (!is_child_of_nonroot)
2467 ast_set_priority(ast_opt_high_priority);
2469 if (!is_child_of_nonroot && rungroup) {
2470 struct group *gr;
2471 gr = getgrnam(rungroup);
2472 if (!gr) {
2473 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2474 exit(1);
2476 if (setgid(gr->gr_gid)) {
2477 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2478 exit(1);
2480 if (setgroups(0, NULL)) {
2481 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2482 exit(1);
2484 if (option_verbose)
2485 ast_verbose("Running as group '%s'\n", rungroup);
2488 if (!is_child_of_nonroot && runuser) {
2489 struct passwd *pw;
2490 pw = getpwnam(runuser);
2491 if (!pw) {
2492 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2493 exit(1);
2495 if (!rungroup) {
2496 if (setgid(pw->pw_gid)) {
2497 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2498 exit(1);
2500 if (initgroups(pw->pw_name, pw->pw_gid)) {
2501 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2502 exit(1);
2505 if (setuid(pw->pw_uid)) {
2506 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2507 exit(1);
2509 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2510 if (option_verbose)
2511 ast_verbose("Running as user '%s'\n", runuser);
2514 #endif /* __CYGWIN__ */
2516 #ifdef linux
2517 if (geteuid() && ast_opt_dump_core) {
2518 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2519 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2522 #endif
2524 term_init();
2525 printf(term_end());
2526 fflush(stdout);
2528 if (ast_opt_console && !option_verbose)
2529 ast_verbose("[ Initializing Custom Configuration Options ]");
2530 /* custom config setup */
2531 register_config_cli();
2532 read_config_maps();
2534 if (ast_opt_console) {
2535 if (el_hist == NULL || el == NULL)
2536 ast_el_initialize();
2538 if (!ast_strlen_zero(filename))
2539 ast_el_read_history(filename);
2542 if (ast_tryconnect()) {
2543 /* One is already running */
2544 if (ast_opt_remote) {
2545 if (ast_opt_exec) {
2546 ast_remotecontrol(xarg);
2547 quit_handler(0, 0, 0, 0);
2548 exit(0);
2550 printf(term_quit());
2551 ast_register_verbose(console_verboser);
2552 WELCOME_MESSAGE;
2553 ast_remotecontrol(NULL);
2554 quit_handler(0, 0, 0, 0);
2555 exit(0);
2556 } else {
2557 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2558 printf(term_quit());
2559 exit(1);
2561 } else if (ast_opt_remote || ast_opt_exec) {
2562 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2563 printf(term_quit());
2564 exit(1);
2566 /* Blindly write pid file since we couldn't connect */
2567 unlink(ast_config_AST_PID);
2568 f = fopen(ast_config_AST_PID, "w");
2569 if (f) {
2570 fprintf(f, "%ld\n", (long)getpid());
2571 fclose(f);
2572 } else
2573 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2575 if (ast_opt_always_fork || !ast_opt_no_fork) {
2576 daemon(0, 0);
2577 ast_mainpid = getpid();
2578 /* Blindly re-write pid file since we are forking */
2579 unlink(ast_config_AST_PID);
2580 f = fopen(ast_config_AST_PID, "w");
2581 if (f) {
2582 fprintf(f, "%ld\n", (long)ast_mainpid);
2583 fclose(f);
2584 } else
2585 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2588 /* Test recursive mutex locking. */
2589 if (test_for_thread_safety())
2590 ast_verbose("Warning! Asterisk is not thread safe.\n");
2592 ast_makesocket();
2593 sigemptyset(&sigs);
2594 sigaddset(&sigs, SIGHUP);
2595 sigaddset(&sigs, SIGTERM);
2596 sigaddset(&sigs, SIGINT);
2597 sigaddset(&sigs, SIGPIPE);
2598 sigaddset(&sigs, SIGWINCH);
2599 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2600 if (ast_opt_console || option_verbose || ast_opt_remote)
2601 ast_register_verbose(console_verboser);
2602 /* Print a welcome message if desired */
2603 if (option_verbose || ast_opt_console) {
2604 WELCOME_MESSAGE;
2606 if (ast_opt_console && !option_verbose)
2607 ast_verbose("[ Booting...");
2609 signal(SIGURG, urg_handler);
2610 signal(SIGINT, __quit_handler);
2611 signal(SIGTERM, __quit_handler);
2612 signal(SIGHUP, hup_handler);
2613 signal(SIGCHLD, child_handler);
2614 signal(SIGPIPE, SIG_IGN);
2616 /* ensure that the random number generators are seeded with a different value every time
2617 Asterisk is started
2619 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2620 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2622 if (init_logger()) {
2623 printf(term_quit());
2624 exit(1);
2626 if (dnsmgr_init()) {
2627 printf(term_quit());
2628 exit(1);
2630 /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2631 if (load_modules(1)) {
2632 printf(term_quit());
2633 exit(1);
2635 ast_http_init();
2636 ast_channels_init();
2637 if (init_manager()) {
2638 printf(term_quit());
2639 exit(1);
2641 if (ast_cdr_engine_init()) {
2642 printf(term_quit());
2643 exit(1);
2645 if (ast_device_state_engine_init()) {
2646 printf(term_quit());
2647 exit(1);
2649 ast_rtp_init();
2650 ast_udptl_init();
2651 if (ast_image_init()) {
2652 printf(term_quit());
2653 exit(1);
2655 if (ast_file_init()) {
2656 printf(term_quit());
2657 exit(1);
2659 if (load_pbx()) {
2660 printf(term_quit());
2661 exit(1);
2663 if (load_modules(0)) {
2664 printf(term_quit());
2665 exit(1);
2667 if (init_framer()) {
2668 printf(term_quit());
2669 exit(1);
2671 if (astdb_init()) {
2672 printf(term_quit());
2673 exit(1);
2675 if (ast_enum_init()) {
2676 printf(term_quit());
2677 exit(1);
2680 dnsmgr_start_refresh();
2682 #if 0
2683 /* This should no longer be necessary */
2684 /* sync cust config and reload some internals in case a custom config handler binded to them */
2685 read_ast_cust_config();
2686 reload_logger(0);
2687 reload_manager();
2688 ast_enum_reload();
2689 ast_rtp_reload();
2690 #endif
2692 /* We might have the option of showing a console, but for now just
2693 do nothing... */
2694 if (ast_opt_console && !option_verbose)
2695 ast_verbose(" ]\n");
2696 if (option_verbose || ast_opt_console)
2697 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2698 if (ast_opt_no_fork)
2699 consolethread = pthread_self();
2700 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2701 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2702 #ifdef __AST_DEBUG_MALLOC
2703 __ast_mm_init();
2704 #endif
2705 time(&ast_startuptime);
2706 ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2707 if (ast_opt_console) {
2708 /* Console stuff now... */
2709 /* Register our quit function */
2710 char title[256];
2711 set_icon("Asterisk");
2712 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2713 set_title(title);
2715 for (;;) {
2716 buf = (char *)el_gets(el, &num);
2717 if (buf) {
2718 if (buf[strlen(buf)-1] == '\n')
2719 buf[strlen(buf)-1] = '\0';
2721 consolehandler((char *)buf);
2722 } else {
2723 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2724 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2725 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2726 int fd;
2727 fd = open("/dev/null", O_RDWR);
2728 if (fd > -1) {
2729 dup2(fd, STDOUT_FILENO);
2730 dup2(fd, STDIN_FILENO);
2731 } else
2732 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2733 break;
2739 /* Do nothing */
2740 for(;;) { /* apparently needed for the MACos */
2741 struct pollfd p = { -1 /* no descriptor */, 0, 0 };
2742 poll(&p, 0, -1);
2744 return 0;