officially deprecate the 'roundrobin' queue strategy in favor of 'rrmemory'
[asterisk-bristuff.git] / asterisk.c
blobaa235c7d02add0db6cbd0e6e6473af448474051b
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 <unistd.h>
61 #include <stdlib.h>
62 #include <sys/time.h>
63 #include <fcntl.h>
64 #include <stdio.h>
65 #include <signal.h>
66 #include <sched.h>
67 #include <sys/socket.h>
68 #include <sys/un.h>
69 #include <sys/wait.h>
70 #include <string.h>
71 #include <errno.h>
72 #include <ctype.h>
73 #include <sys/resource.h>
74 #include <grp.h>
75 #include <pwd.h>
76 #include <sys/stat.h>
77 #ifdef linux
78 #include <sys/prctl.h>
79 #endif
80 #include <regex.h>
82 #ifdef linux
83 #include <sys/prctl.h>
84 #endif
86 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
87 #include <netdb.h>
88 #if defined(SOLARIS)
89 extern int daemon(int, int); /* defined in libresolv of all places */
90 #endif
91 #endif
93 #include "asterisk.h"
95 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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"
125 #include "asterisk/compat.h"
127 #include "asterisk/doxyref.h" /* Doxygen documentation */
129 #include "defaults.h"
131 #ifndef AF_LOCAL
132 #define AF_LOCAL AF_UNIX
133 #define PF_LOCAL PF_UNIX
134 #endif
136 #define AST_MAX_CONNECTS 128
137 #define NUM_MSGS 64
139 /*! \brief Welcome message when starting a CLI interface */
140 #define WELCOME_MESSAGE \
141 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
142 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
143 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
144 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
145 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
146 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
147 ast_verbose("=========================================================================\n")
149 /*! \defgroup main_options
150 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
151 the operating system command line when starting Asterisk
152 Some of them can be changed in the CLI
154 /*! @{ */
156 extern int ast_language_is_prefix; /* XXX move to some header */
158 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
160 int option_verbose = 0; /*!< Verbosity level */
161 int option_debug = 0; /*!< Debug level */
163 double option_maxload = 0.0; /*!< Max load avg on system */
164 int option_maxcalls = 0; /*!< Max number of active calls */
166 /*! @} */
168 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
169 char debug_filename[AST_FILENAME_MAX] = "";
171 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
172 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
173 pid_t ast_mainpid;
174 struct console {
175 int fd; /*!< File descriptor */
176 int p[2]; /*!< Pipe */
177 pthread_t t; /*!< Thread of handler */
178 int mute; /*!< Is the console muted for logs */
181 struct ast_atexit {
182 void (*func)(void);
183 AST_LIST_ENTRY(ast_atexit) list;
186 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
188 time_t ast_startuptime;
189 time_t ast_lastreloadtime;
191 static History *el_hist = NULL;
192 static EditLine *el = NULL;
193 static char *remotehostname;
195 struct console consoles[AST_MAX_CONNECTS];
197 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
199 static int ast_el_add_history(char *);
200 static int ast_el_read_history(char *);
201 static int ast_el_write_history(char *);
203 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
204 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
205 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
206 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
207 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
208 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
209 char ast_config_AST_DATA_DIR[AST_CONFIG_MAX_PATH];
210 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
211 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
212 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
213 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
214 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
215 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
216 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
217 char ast_config_AST_RUN_USER[AST_CONFIG_MAX_PATH];
218 char ast_config_AST_RUN_GROUP[AST_CONFIG_MAX_PATH];
219 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
220 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
221 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
222 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
223 char ast_config_AST_SYSTEM_NAME[20] = "";
225 extern const char *ast_build_hostname;
226 extern const char *ast_build_kernel;
227 extern const char *ast_build_machine;
228 extern const char *ast_build_os;
229 extern const char *ast_build_date;
230 extern const char *ast_build_user;
232 static char *_argv[256];
233 static int shuttingdown = 0;
234 static int restartnow = 0;
235 static pthread_t consolethread = AST_PTHREADT_NULL;
237 static char randompool[256];
239 #if !defined(LOW_MEMORY)
240 struct file_version {
241 AST_LIST_ENTRY(file_version) list;
242 const char *file;
243 char *version;
246 static AST_LIST_HEAD_STATIC(file_versions, file_version);
248 void ast_register_file_version(const char *file, const char *version)
250 struct file_version *new;
251 char *work;
252 size_t version_length;
254 work = ast_strdupa(version);
255 work = ast_strip(ast_strip_quoted(work, "$", "$"));
256 version_length = strlen(work) + 1;
258 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
259 return;
261 new->file = file;
262 new->version = (char *) new + sizeof(*new);
263 memcpy(new->version, work, version_length);
264 AST_LIST_LOCK(&file_versions);
265 AST_LIST_INSERT_HEAD(&file_versions, new, list);
266 AST_LIST_UNLOCK(&file_versions);
269 void ast_unregister_file_version(const char *file)
271 struct file_version *find;
273 AST_LIST_LOCK(&file_versions);
274 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
275 if (!strcasecmp(find->file, file)) {
276 AST_LIST_REMOVE_CURRENT(&file_versions, list);
277 break;
280 AST_LIST_TRAVERSE_SAFE_END;
281 AST_LIST_UNLOCK(&file_versions);
282 if (find)
283 free(find);
286 struct thread_list_t {
287 AST_LIST_ENTRY(thread_list_t) list;
288 char *name;
289 pthread_t id;
292 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
294 static char show_threads_help[] =
295 "Usage: show threads\n"
296 " List threads currently active in the system.\n";
298 void ast_register_thread(char *name)
300 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
302 if (!new)
303 return;
304 new->id = pthread_self();
305 new->name = name; /* this was a copy already */
306 AST_LIST_LOCK(&thread_list);
307 AST_LIST_INSERT_HEAD(&thread_list, new, list);
308 AST_LIST_UNLOCK(&thread_list);
311 void ast_unregister_thread(void *id)
313 struct thread_list_t *x;
315 AST_LIST_LOCK(&thread_list);
316 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
317 if ((void *)x->id == id) {
318 AST_LIST_REMOVE_CURRENT(&thread_list, list);
319 break;
322 AST_LIST_TRAVERSE_SAFE_END;
323 AST_LIST_UNLOCK(&thread_list);
324 if (x) {
325 free(x->name);
326 free(x);
330 static int handle_show_threads(int fd, int argc, char *argv[])
332 int count = 0;
333 struct thread_list_t *cur;
335 AST_LIST_LOCK(&thread_list);
336 AST_LIST_TRAVERSE(&thread_list, cur, list) {
337 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
338 count++;
340 AST_LIST_UNLOCK(&thread_list);
341 ast_cli(fd, "%d threads listed.\n", count);
342 return 0;
345 struct profile_entry {
346 const char *name;
347 uint64_t scale; /* if non-zero, values are scaled by this */
348 int64_t mark;
349 int64_t value;
350 int64_t events;
353 struct profile_data {
354 int entries;
355 int max_size;
356 struct profile_entry e[0];
359 static struct profile_data *prof_data;
362 * allocates a counter with a given name and scale.
363 * Returns the identifier of the counter.
365 int ast_add_profile(const char *name, uint64_t scale)
367 int l = sizeof(struct profile_data);
368 int n = 10; /* default entries */
370 if (prof_data == NULL) {
371 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
372 if (prof_data == NULL)
373 return -1;
374 prof_data->entries = 0;
375 prof_data->max_size = n;
377 if (prof_data->entries >= prof_data->max_size) {
378 void *p;
379 n = prof_data->max_size + 20;
380 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
381 if (p == NULL)
382 return -1;
383 prof_data = p;
384 prof_data->max_size = n;
386 n = prof_data->entries++;
387 prof_data->e[n].name = ast_strdup(name);
388 prof_data->e[n].value = 0;
389 prof_data->e[n].events = 0;
390 prof_data->e[n].mark = 0;
391 prof_data->e[n].scale = scale;
392 return n;
395 int64_t ast_profile(int i, int64_t delta)
397 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
398 return 0;
399 if (prof_data->e[i].scale > 1)
400 delta /= prof_data->e[i].scale;
401 prof_data->e[i].value += delta;
402 prof_data->e[i].events++;
403 return prof_data->e[i].value;
406 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
407 #if defined(__FreeBSD__)
408 #include <machine/cpufunc.h>
409 #elif defined(linux)
410 static __inline u_int64_t
411 rdtsc(void)
413 uint64_t rv;
415 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
416 return (rv);
418 #endif
419 #else /* supply a dummy function on other platforms */
420 static __inline u_int64_t
421 rdtsc(void)
423 return 0;
425 #endif
427 int64_t ast_mark(int i, int startstop)
429 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
430 return 0;
431 if (startstop == 1)
432 prof_data->e[i].mark = rdtsc();
433 else {
434 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
435 if (prof_data->e[i].scale > 1)
436 prof_data->e[i].mark /= prof_data->e[i].scale;
437 prof_data->e[i].value += prof_data->e[i].mark;
438 prof_data->e[i].events++;
440 return prof_data->e[i].mark;
443 static int handle_show_profile(int fd, int argc, char *argv[])
445 int i, min, max;
446 char *search = NULL;
448 if (prof_data == NULL)
449 return 0;
451 min = 0;
452 max = prof_data->entries;
453 if (argc >= 3) { /* specific entries */
454 if (isdigit(argv[2][0])) {
455 min = atoi(argv[2]);
456 if (argc == 4 && strcmp(argv[3], "-"))
457 max = atoi(argv[3]);
458 } else
459 search = argv[2];
461 if (max > prof_data->entries)
462 max = prof_data->entries;
463 if (!strcmp(argv[0], "clear")) {
464 for (i= min; i < max; i++) {
465 if (!search || strstr(prof_data->e[i].name, search)) {
466 prof_data->e[i].value = 0;
467 prof_data->e[i].events = 0;
470 return 0;
472 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
473 prof_data->entries, prof_data->max_size);
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",
479 (long)e->scale,
480 (long)e->events, (long long)e->value,
481 (long long)(e->events ? e->value / e->events : e->value),
482 e->name);
484 return 0;
487 static char show_version_files_help[] =
488 "Usage: show version files [like <pattern>]\n"
489 " Shows the revision numbers of the files used to build this copy of Asterisk.\n"
490 " Optional regular expression pattern is used to filter the file list.\n";
492 /*! CLI command to list module versions */
493 static int handle_show_version_files(int fd, int argc, char *argv[])
495 #define FORMAT "%-25.25s %-40.40s\n"
496 struct file_version *iterator;
497 regex_t regexbuf;
498 int havepattern = 0;
499 int havename = 0;
500 int count_files = 0;
502 switch (argc) {
503 case 5:
504 if (!strcasecmp(argv[3], "like")) {
505 if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
506 return RESULT_SHOWUSAGE;
507 havepattern = 1;
508 } else
509 return RESULT_SHOWUSAGE;
510 break;
511 case 4:
512 havename = 1;
513 break;
514 case 3:
515 break;
516 default:
517 return RESULT_SHOWUSAGE;
520 ast_cli(fd, FORMAT, "File", "Revision");
521 ast_cli(fd, FORMAT, "----", "--------");
522 AST_LIST_LOCK(&file_versions);
523 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
524 if (havename && strcasecmp(iterator->file, argv[3]))
525 continue;
527 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
528 continue;
530 ast_cli(fd, FORMAT, iterator->file, iterator->version);
531 count_files++;
532 if (havename)
533 break;
535 AST_LIST_UNLOCK(&file_versions);
536 if (!havename) {
537 ast_cli(fd, "%d files listed.\n", count_files);
540 if (havepattern)
541 regfree(&regexbuf);
543 return RESULT_SUCCESS;
544 #undef FORMAT
547 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
549 struct file_version *find;
550 int which = 0;
551 char *ret = NULL;
552 int matchlen = strlen(word);
554 if (pos != 3)
555 return NULL;
557 AST_LIST_LOCK(&file_versions);
558 AST_LIST_TRAVERSE(&file_versions, find, list) {
559 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
560 ret = ast_strdup(find->file);
561 break;
564 AST_LIST_UNLOCK(&file_versions);
566 return ret;
568 #endif /* ! LOW_MEMORY */
570 int ast_register_atexit(void (*func)(void))
572 int res = -1;
573 struct ast_atexit *ae;
574 ast_unregister_atexit(func);
575 AST_LIST_LOCK(&atexits);
576 if ((ae = ast_calloc(1, sizeof(*ae)))) {
577 AST_LIST_INSERT_HEAD(&atexits, ae, list);
578 ae->func = func;
579 res = 0;
581 AST_LIST_UNLOCK(&atexits);
582 return res;
585 void ast_unregister_atexit(void (*func)(void))
587 struct ast_atexit *ae;
588 AST_LIST_LOCK(&atexits);
589 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
590 if (ae->func == func) {
591 AST_LIST_REMOVE_CURRENT(&atexits, list);
592 break;
595 AST_LIST_TRAVERSE_SAFE_END
596 AST_LIST_UNLOCK(&atexits);
599 static int fdprint(int fd, const char *s)
601 return write(fd, s, strlen(s) + 1);
604 /*! NULL handler so we can collect the child exit status */
605 static void null_sig_handler(int signal)
610 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
611 /*! Keep track of how many threads are currently trying to wait*() on
612 * a child process */
613 static unsigned int safe_system_level = 0;
614 static void *safe_system_prev_handler;
616 void ast_replace_sigchld(void)
618 unsigned int level;
620 ast_mutex_lock(&safe_system_lock);
621 level = safe_system_level++;
623 /* only replace the handler if it has not already been done */
624 if (level == 0)
625 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
627 ast_mutex_unlock(&safe_system_lock);
630 void ast_unreplace_sigchld(void)
632 unsigned int level;
634 ast_mutex_lock(&safe_system_lock);
635 level = --safe_system_level;
637 /* only restore the handler if we are the last one */
638 if (level == 0)
639 signal(SIGCHLD, safe_system_prev_handler);
641 ast_mutex_unlock(&safe_system_lock);
644 int ast_safe_system(const char *s)
646 pid_t pid;
647 int x;
648 int res;
649 struct rusage rusage;
650 int status;
652 ast_replace_sigchld();
654 pid = fork();
656 if (pid == 0) {
657 if (ast_opt_high_priority)
658 ast_set_priority(0);
659 /* Close file descriptors and launch system command */
660 for (x = STDERR_FILENO + 1; x < 4096; x++)
661 close(x);
662 execl("/bin/sh", "/bin/sh", "-c", s, NULL);
663 exit(1);
664 } else if (pid > 0) {
665 for(;;) {
666 res = wait4(pid, &status, 0, &rusage);
667 if (res > -1) {
668 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
669 break;
670 } else if (errno != EINTR)
671 break;
673 } else {
674 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
675 res = -1;
678 ast_unreplace_sigchld();
680 return res;
684 * mute or unmute a console from logging
686 void ast_console_toggle_mute(int fd) {
687 int x;
688 for (x = 0;x < AST_MAX_CONNECTS; x++) {
689 if (fd == consoles[x].fd) {
690 if (consoles[x].mute) {
691 consoles[x].mute = 0;
692 ast_cli(fd, "Console is not muted anymore.\n");
693 } else {
694 consoles[x].mute = 1;
695 ast_cli(fd, "Console is muted.\n");
697 return;
700 ast_cli(fd, "Couldn't find remote console.\n");
704 * log the string to all attached console clients
706 static void ast_network_puts_mutable(const char *string)
708 int x;
709 for (x = 0;x < AST_MAX_CONNECTS; x++) {
710 if (consoles[x].mute)
711 continue;
712 if (consoles[x].fd > -1)
713 fdprint(consoles[x].p[1], string);
718 * log the string to the console, and all attached
719 * console clients
721 void ast_console_puts_mutable(const char *string)
723 fputs(string, stdout);
724 fflush(stdout);
725 ast_network_puts_mutable(string);
729 * write the string to all attached console clients
731 static void ast_network_puts(const char *string)
733 int x;
734 for (x=0; x < AST_MAX_CONNECTS; x++) {
735 if (consoles[x].fd > -1)
736 fdprint(consoles[x].p[1], string);
741 * write the string to the console, and all attached
742 * console clients
744 void ast_console_puts(const char *string)
746 fputs(string, stdout);
747 fflush(stdout);
748 ast_network_puts(string);
751 static void network_verboser(const char *s, int pos, int replace, int complete)
752 /* ARGUSED */
754 if (replace) {
755 char *t;
756 if ((t = alloca(strlen(s) + 2))) {
757 sprintf(t, "\r%s", s);
758 if (complete)
759 ast_network_puts_mutable(t);
760 } else {
761 ast_log(LOG_ERROR, "Out of memory\n");
762 ast_network_puts_mutable(s);
764 } else {
765 if (complete)
766 ast_network_puts_mutable(s);
770 static pthread_t lthread;
772 static void *netconsole(void *vconsole)
774 struct console *con = vconsole;
775 char hostname[MAXHOSTNAMELEN] = "";
776 char tmp[512];
777 int res;
778 struct pollfd fds[2];
780 if (gethostname(hostname, sizeof(hostname)-1))
781 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
782 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
783 fdprint(con->fd, tmp);
784 for(;;) {
785 fds[0].fd = con->fd;
786 fds[0].events = POLLIN;
787 fds[0].revents = 0;
788 fds[1].fd = con->p[0];
789 fds[1].events = POLLIN;
790 fds[1].revents = 0;
792 res = poll(fds, 2, -1);
793 if (res < 0) {
794 if (errno != EINTR)
795 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
796 continue;
798 if (fds[0].revents) {
799 res = read(con->fd, tmp, sizeof(tmp));
800 if (res < 1) {
801 break;
803 tmp[res] = 0;
804 ast_cli_command(con->fd, tmp);
806 if (fds[1].revents) {
807 res = read(con->p[0], tmp, sizeof(tmp));
808 if (res < 1) {
809 ast_log(LOG_ERROR, "read returned %d\n", res);
810 break;
812 res = write(con->fd, tmp, res);
813 if (res < 1)
814 break;
817 if (option_verbose > 2)
818 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
819 close(con->fd);
820 close(con->p[0]);
821 close(con->p[1]);
822 con->fd = -1;
824 return NULL;
827 static void *listener(void *unused)
829 struct sockaddr_un sunaddr;
830 int s;
831 socklen_t len;
832 int x;
833 int flags;
834 struct pollfd fds[1];
835 pthread_attr_t attr;
836 pthread_attr_init(&attr);
837 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
838 for (;;) {
839 if (ast_socket < 0)
840 return NULL;
841 fds[0].fd = ast_socket;
842 fds[0].events = POLLIN;
843 s = poll(fds, 1, -1);
844 if (s < 0) {
845 if (errno != EINTR)
846 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
847 continue;
849 len = sizeof(sunaddr);
850 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
851 if (s < 0) {
852 if (errno != EINTR)
853 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
854 } else {
855 for (x = 0; x < AST_MAX_CONNECTS; x++) {
856 if (consoles[x].fd < 0) {
857 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
858 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
859 consoles[x].fd = -1;
860 fdprint(s, "Server failed to create pipe\n");
861 close(s);
862 break;
864 flags = fcntl(consoles[x].p[1], F_GETFL);
865 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
866 consoles[x].fd = s;
867 consoles[x].mute = ast_opt_mute;
868 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
869 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
870 close(consoles[x].p[0]);
871 close(consoles[x].p[1]);
872 consoles[x].fd = -1;
873 fdprint(s, "Server failed to spawn thread\n");
874 close(s);
876 break;
879 if (x >= AST_MAX_CONNECTS) {
880 fdprint(s, "No more connections allowed\n");
881 ast_log(LOG_WARNING, "No more connections allowed\n");
882 close(s);
883 } else if (consoles[x].fd > -1) {
884 if (option_verbose > 2)
885 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
889 return NULL;
892 static int ast_makesocket(void)
894 struct sockaddr_un sunaddr;
895 int res;
896 int x;
897 uid_t uid = -1;
898 gid_t gid = -1;
900 for (x = 0; x < AST_MAX_CONNECTS; x++)
901 consoles[x].fd = -1;
902 unlink(ast_config_AST_SOCKET);
903 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
904 if (ast_socket < 0) {
905 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
906 return -1;
908 memset(&sunaddr, 0, sizeof(sunaddr));
909 sunaddr.sun_family = AF_LOCAL;
910 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
911 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
912 if (res) {
913 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
914 close(ast_socket);
915 ast_socket = -1;
916 return -1;
918 res = listen(ast_socket, 2);
919 if (res < 0) {
920 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
921 close(ast_socket);
922 ast_socket = -1;
923 return -1;
925 ast_register_verbose(network_verboser);
926 ast_pthread_create(&lthread, NULL, listener, NULL);
928 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
929 struct passwd *pw;
930 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
931 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
932 } else {
933 uid = pw->pw_uid;
937 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
938 struct group *grp;
939 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
940 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
941 } else {
942 gid = grp->gr_gid;
946 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
947 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
949 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
950 int p1;
951 mode_t p;
952 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
953 p = p1;
954 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
955 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
958 return 0;
961 static int ast_tryconnect(void)
963 struct sockaddr_un sunaddr;
964 int res;
965 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
966 if (ast_consock < 0) {
967 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
968 return 0;
970 memset(&sunaddr, 0, sizeof(sunaddr));
971 sunaddr.sun_family = AF_LOCAL;
972 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
973 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
974 if (res) {
975 close(ast_consock);
976 ast_consock = -1;
977 return 0;
978 } else
979 return 1;
982 /*! 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
986 SLD: seems to be some pthread activity relating to the printf anyway:
987 which is leading to a deadlock?
989 static void urg_handler(int num)
991 #if 0
992 if (option_debug > 2)
993 printf("-- Asterisk Urgent handler\n");
994 #endif
995 signal(num, urg_handler);
996 return;
999 static void hup_handler(int num)
1001 if (option_verbose > 1)
1002 printf("Received HUP signal -- Reloading configs\n");
1003 if (restartnow)
1004 execvp(_argv[0], _argv);
1005 /* XXX This could deadlock XXX */
1006 ast_module_reload(NULL);
1007 signal(num, hup_handler);
1010 static void child_handler(int sig)
1012 /* Must not ever ast_log or ast_verbose within signal handler */
1013 int n, status;
1016 * Reap all dead children -- not just one
1018 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1020 if (n == 0 && option_debug)
1021 printf("Huh? Child handler, but nobody there?\n");
1022 signal(sig, child_handler);
1025 /*! Set an X-term or screen title */
1026 static void set_title(char *text)
1028 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1029 fprintf(stdout, "\033]2;%s\007", text);
1032 static void set_icon(char *text)
1034 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1035 fprintf(stdout, "\033]1;%s\007", text);
1038 /*! We set ourselves to a high priority, that we might pre-empt everything
1039 else. If your PBX has heavy activity on it, this is a good thing. */
1040 int ast_set_priority(int pri)
1042 struct sched_param sched;
1043 memset(&sched, 0, sizeof(sched));
1044 #ifdef __linux__
1045 if (pri) {
1046 sched.sched_priority = 10;
1047 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1048 ast_log(LOG_WARNING, "Unable to set high priority\n");
1049 return -1;
1050 } else
1051 if (option_verbose)
1052 ast_verbose("Set to realtime thread\n");
1053 } else {
1054 sched.sched_priority = 0;
1055 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
1056 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1057 return -1;
1060 #else
1061 if (pri) {
1062 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1063 ast_log(LOG_WARNING, "Unable to set high priority\n");
1064 return -1;
1065 } else
1066 if (option_verbose)
1067 ast_verbose("Set to high priority\n");
1068 } else {
1069 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1070 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1071 return -1;
1074 #endif
1075 return 0;
1078 static void ast_run_atexits(void)
1080 struct ast_atexit *ae;
1081 AST_LIST_LOCK(&atexits);
1082 AST_LIST_TRAVERSE(&atexits, ae, list) {
1083 if (ae->func)
1084 ae->func();
1086 AST_LIST_UNLOCK(&atexits);
1089 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1091 char filename[80] = "";
1092 time_t s,e;
1093 int x;
1094 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1095 ast_cdr_engine_term();
1096 if (safeshutdown) {
1097 shuttingdown = 1;
1098 if (!nice) {
1099 /* Begin shutdown routine, hanging up active channels */
1100 ast_begin_shutdown(1);
1101 if (option_verbose && ast_opt_console)
1102 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1103 time(&s);
1104 for (;;) {
1105 time(&e);
1106 /* Wait up to 15 seconds for all channels to go away */
1107 if ((e - s) > 15)
1108 break;
1109 if (!ast_active_channels())
1110 break;
1111 if (!shuttingdown)
1112 break;
1113 /* Sleep 1/10 of a second */
1114 usleep(100000);
1116 } else {
1117 if (nice < 2)
1118 ast_begin_shutdown(0);
1119 if (option_verbose && ast_opt_console)
1120 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1121 for (;;) {
1122 if (!ast_active_channels())
1123 break;
1124 if (!shuttingdown)
1125 break;
1126 sleep(1);
1130 if (!shuttingdown) {
1131 if (option_verbose && ast_opt_console)
1132 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1133 return;
1136 if (ast_opt_console || ast_opt_remote) {
1137 if (getenv("HOME"))
1138 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1139 if (!ast_strlen_zero(filename))
1140 ast_el_write_history(filename);
1141 if (el != NULL)
1142 el_end(el);
1143 if (el_hist != NULL)
1144 history_end(el_hist);
1146 if (option_verbose)
1147 ast_verbose("Executing last minute cleanups\n");
1148 ast_run_atexits();
1149 /* Called on exit */
1150 if (option_verbose && ast_opt_console)
1151 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1152 else if (option_debug)
1153 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1154 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1155 if (ast_socket > -1) {
1156 close(ast_socket);
1157 ast_socket = -1;
1158 unlink(ast_config_AST_SOCKET);
1159 pthread_cancel(lthread);
1161 if (ast_consock > -1)
1162 close(ast_consock);
1163 if (!ast_opt_remote)
1164 unlink(ast_config_AST_PID);
1165 printf(term_quit());
1166 if (restart) {
1167 if (option_verbose || ast_opt_console)
1168 ast_verbose("Preparing for Asterisk restart...\n");
1169 /* Mark all FD's for closing on exec */
1170 for (x=3; x < 32768; x++) {
1171 fcntl(x, F_SETFD, FD_CLOEXEC);
1173 if (option_verbose || ast_opt_console)
1174 ast_verbose("Restarting Asterisk NOW...\n");
1175 restartnow = 1;
1177 /* close logger */
1178 close_logger();
1180 /* If there is a consolethread running send it a SIGHUP
1181 so it can execvp, otherwise we can do it ourselves */
1182 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1183 pthread_kill(consolethread, SIGHUP);
1184 /* Give the signal handler some time to complete */
1185 sleep(2);
1186 } else
1187 execvp(_argv[0], _argv);
1189 } else {
1190 /* close logger */
1191 close_logger();
1193 exit(0);
1196 static void __quit_handler(int num)
1198 quit_handler(num, 0, 1, 0);
1201 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1203 const char *c;
1204 if (!strncmp(s, cmp, strlen(cmp))) {
1205 c = s + strlen(cmp);
1206 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1207 return c;
1209 return NULL;
1212 static void console_verboser(const char *s, int pos, int replace, int complete)
1214 char tmp[80];
1215 const char *c = NULL;
1216 /* Return to the beginning of the line */
1217 if (!pos) {
1218 fprintf(stdout, "\r");
1219 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1220 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1221 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1222 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
1223 fputs(tmp, stdout);
1225 if (c)
1226 fputs(c + pos,stdout);
1227 else
1228 fputs(s + pos,stdout);
1229 fflush(stdout);
1230 if (complete) {
1231 /* Wake up a poll()ing console */
1232 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1233 pthread_kill(consolethread, SIGURG);
1237 static int ast_all_zeros(char *s)
1239 while (*s) {
1240 if (*s > 32)
1241 return 0;
1242 s++;
1244 return 1;
1247 static void consolehandler(char *s)
1249 printf(term_end());
1250 fflush(stdout);
1251 /* Called when readline data is available */
1252 if (s && !ast_all_zeros(s))
1253 ast_el_add_history(s);
1254 /* Give the console access to the shell */
1255 if (s) {
1256 /* The real handler for bang */
1257 if (s[0] == '!') {
1258 if (s[1])
1259 ast_safe_system(s+1);
1260 else
1261 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1262 } else
1263 ast_cli_command(STDOUT_FILENO, s);
1264 } else
1265 fprintf(stdout, "\nUse \"quit\" to exit\n");
1268 static int remoteconsolehandler(char *s)
1270 int ret = 0;
1271 /* Called when readline data is available */
1272 if (s && !ast_all_zeros(s))
1273 ast_el_add_history(s);
1274 /* Give the console access to the shell */
1275 if (s) {
1276 /* The real handler for bang */
1277 if (s[0] == '!') {
1278 if (s[1])
1279 ast_safe_system(s+1);
1280 else
1281 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1282 ret = 1;
1284 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1285 (s[4] == '\0' || isspace(s[4]))) {
1286 quit_handler(0, 0, 0, 0);
1287 ret = 1;
1289 } else
1290 fprintf(stdout, "\nUse \"quit\" to exit\n");
1292 return ret;
1295 static char abort_halt_help[] =
1296 "Usage: abort shutdown\n"
1297 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1298 " call operations.\n";
1300 static char shutdown_now_help[] =
1301 "Usage: stop now\n"
1302 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1304 static char shutdown_gracefully_help[] =
1305 "Usage: stop gracefully\n"
1306 " Causes Asterisk to not accept new calls, and exit when all\n"
1307 " active calls have terminated normally.\n";
1309 static char shutdown_when_convenient_help[] =
1310 "Usage: stop when convenient\n"
1311 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1313 static char restart_now_help[] =
1314 "Usage: restart now\n"
1315 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1316 " restart.\n";
1318 static char restart_gracefully_help[] =
1319 "Usage: restart gracefully\n"
1320 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1321 " restart when all active calls have ended.\n";
1323 static char restart_when_convenient_help[] =
1324 "Usage: restart when convenient\n"
1325 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1327 static char bang_help[] =
1328 "Usage: !<command>\n"
1329 " Executes a given shell command\n";
1331 static char show_warranty_help[] =
1332 "Usage: show warranty\n"
1333 " Shows the warranty (if any) for this copy of Asterisk.\n";
1335 static char show_license_help[] =
1336 "Usage: show license\n"
1337 " Shows the license(s) for this copy of Asterisk.\n";
1339 static char version_help[] =
1340 "Usage: show version\n"
1341 " Shows Asterisk version information.\n";
1343 static int handle_version(int fd, int argc, char *argv[])
1345 if (argc != 2)
1346 return RESULT_SHOWUSAGE;
1347 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1348 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1349 ast_build_machine, ast_build_os, ast_build_date);
1350 return RESULT_SUCCESS;
1353 #if 0
1354 static int handle_quit(int fd, int argc, char *argv[])
1356 if (argc != 1)
1357 return RESULT_SHOWUSAGE;
1358 quit_handler(0, 0, 1, 0);
1359 return RESULT_SUCCESS;
1361 #endif
1363 static int handle_shutdown_now(int fd, int argc, char *argv[])
1365 if (argc != 2)
1366 return RESULT_SHOWUSAGE;
1367 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1368 return RESULT_SUCCESS;
1371 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1373 if (argc != 2)
1374 return RESULT_SHOWUSAGE;
1375 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1376 return RESULT_SUCCESS;
1379 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1381 if (argc != 3)
1382 return RESULT_SHOWUSAGE;
1383 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1384 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1385 return RESULT_SUCCESS;
1388 static int handle_restart_now(int fd, int argc, char *argv[])
1390 if (argc != 2)
1391 return RESULT_SHOWUSAGE;
1392 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1393 return RESULT_SUCCESS;
1396 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1398 if (argc != 2)
1399 return RESULT_SHOWUSAGE;
1400 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1401 return RESULT_SUCCESS;
1404 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1406 if (argc != 3)
1407 return RESULT_SHOWUSAGE;
1408 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1409 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1410 return RESULT_SUCCESS;
1413 static int handle_abort_halt(int fd, int argc, char *argv[])
1415 if (argc != 2)
1416 return RESULT_SHOWUSAGE;
1417 ast_cancel_shutdown();
1418 shuttingdown = 0;
1419 return RESULT_SUCCESS;
1422 static int handle_bang(int fd, int argc, char *argv[])
1424 return RESULT_SUCCESS;
1426 static const char *warranty_lines[] = {
1427 "\n",
1428 " NO WARRANTY\n",
1429 "\n",
1430 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1431 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1432 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1433 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1434 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1435 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1436 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1437 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1438 "REPAIR OR CORRECTION.\n",
1439 "\n",
1440 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1441 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1442 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1443 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1444 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1445 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1446 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1447 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1448 "POSSIBILITY OF SUCH DAMAGES.\n",
1451 static int show_warranty(int fd, int argc, char *argv[])
1453 int x;
1455 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1456 ast_cli(fd, (char *) warranty_lines[x]);
1458 return RESULT_SUCCESS;
1461 static const char *license_lines[] = {
1462 "\n",
1463 "This program is free software; you can redistribute it and/or modify\n",
1464 "it under the terms of the GNU General Public License version 2 as\n",
1465 "published by the Free Software Foundation.\n",
1466 "\n",
1467 "This program also contains components licensed under other licenses.\n",
1468 "They include:\n",
1469 "\n",
1470 "This program is distributed in the hope that it will be useful,\n",
1471 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1472 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1473 "GNU General Public License for more details.\n",
1474 "\n",
1475 "You should have received a copy of the GNU General Public License\n",
1476 "along with this program; if not, write to the Free Software\n",
1477 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1480 static int show_license(int fd, int argc, char *argv[])
1482 int x;
1484 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1485 ast_cli(fd, (char *) license_lines[x]);
1487 return RESULT_SUCCESS;
1490 #define ASTERISK_PROMPT "*CLI> "
1492 #define ASTERISK_PROMPT2 "%s*CLI> "
1494 static struct ast_cli_entry core_cli[] = {
1495 { { "abort", "halt", NULL }, handle_abort_halt,
1496 "Cancel a running halt", abort_halt_help },
1497 { { "stop", "now", NULL }, handle_shutdown_now,
1498 "Shut down Asterisk immediately", shutdown_now_help },
1499 { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1500 "Gracefully shut down Asterisk", shutdown_gracefully_help },
1501 { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1502 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1503 { { "restart", "now", NULL }, handle_restart_now,
1504 "Restart Asterisk immediately", restart_now_help },
1505 { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1506 "Restart Asterisk gracefully", restart_gracefully_help },
1507 { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1508 "Restart Asterisk at empty call volume", restart_when_convenient_help },
1509 { { "show", "warranty", NULL }, show_warranty,
1510 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
1511 { { "show", "license", NULL }, show_license,
1512 "Show the license(s) for this copy of Asterisk", show_license_help },
1513 { { "show", "version", NULL }, handle_version,
1514 "Display version info", version_help },
1515 { { "!", NULL }, handle_bang,
1516 "Execute a shell command", bang_help },
1517 #if !defined(LOW_MEMORY)
1518 { { "show", "version", "files", NULL }, handle_show_version_files,
1519 "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1520 { { "show", "threads", NULL }, handle_show_threads,
1521 "Show running threads", show_threads_help, NULL },
1522 { { "show", "profile", NULL }, handle_show_profile,
1523 "Show profiling info"},
1524 { { "clear", "profile", NULL }, handle_show_profile,
1525 "Clear profiling info"},
1526 #endif /* ! LOW_MEMORY */
1529 static int ast_el_read_char(EditLine *el, char *cp)
1531 int num_read = 0;
1532 int lastpos = 0;
1533 struct pollfd fds[2];
1534 int res;
1535 int max;
1536 char buf[512];
1538 for (;;) {
1539 max = 1;
1540 fds[0].fd = ast_consock;
1541 fds[0].events = POLLIN;
1542 if (!ast_opt_exec) {
1543 fds[1].fd = STDIN_FILENO;
1544 fds[1].events = POLLIN;
1545 max++;
1547 res = poll(fds, max, -1);
1548 if (res < 0) {
1549 if (errno == EINTR)
1550 continue;
1551 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1552 break;
1555 if (!ast_opt_exec && fds[1].revents) {
1556 num_read = read(STDIN_FILENO, cp, 1);
1557 if (num_read < 1) {
1558 break;
1559 } else
1560 return (num_read);
1562 if (fds[0].revents) {
1563 res = read(ast_consock, buf, sizeof(buf) - 1);
1564 /* if the remote side disappears exit */
1565 if (res < 1) {
1566 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1567 if (!ast_opt_reconnect) {
1568 quit_handler(0, 0, 0, 0);
1569 } else {
1570 int tries;
1571 int reconnects_per_second = 20;
1572 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1573 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1574 if (ast_tryconnect()) {
1575 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1576 printf(term_quit());
1577 WELCOME_MESSAGE;
1578 break;
1579 } else {
1580 usleep(1000000 / reconnects_per_second);
1583 if (tries >= 30 * reconnects_per_second) {
1584 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1585 quit_handler(0, 0, 0, 0);
1590 buf[res] = '\0';
1592 if (!ast_opt_exec && !lastpos)
1593 write(STDOUT_FILENO, "\r", 1);
1594 write(STDOUT_FILENO, buf, res);
1595 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1596 *cp = CC_REFRESH;
1597 return(1);
1598 } else {
1599 lastpos = 1;
1604 *cp = '\0';
1605 return (0);
1608 static char *cli_prompt(EditLine *el)
1610 static char prompt[200];
1611 char *pfmt;
1612 int color_used = 0;
1613 char term_code[20];
1615 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1616 char *t = pfmt, *p = prompt;
1617 memset(prompt, 0, sizeof(prompt));
1618 while (*t != '\0' && *p < sizeof(prompt)) {
1619 if (*t == '%') {
1620 char hostname[MAXHOSTNAMELEN]="";
1621 int i;
1622 time_t ts;
1623 struct tm tm;
1624 #ifdef linux
1625 FILE *LOADAVG;
1626 #endif
1627 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1629 t++;
1630 switch (*t) {
1631 case 'C': /* color */
1632 t++;
1633 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1634 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1635 t += i - 1;
1636 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1637 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1638 t += i - 1;
1641 /* If the color has been reset correctly, then there's no need to reset it later */
1642 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1643 color_used = 0;
1644 } else {
1645 color_used = 1;
1647 break;
1648 case 'd': /* date */
1649 memset(&tm, 0, sizeof(tm));
1650 time(&ts);
1651 if (localtime_r(&ts, &tm)) {
1652 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1654 break;
1655 case 'h': /* hostname */
1656 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1657 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1658 } else {
1659 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1661 break;
1662 case 'H': /* short hostname */
1663 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1664 for (i = 0; i < sizeof(hostname); i++) {
1665 if (hostname[i] == '.') {
1666 hostname[i] = '\0';
1667 break;
1670 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1671 } else {
1672 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1674 break;
1675 #ifdef linux
1676 case 'l': /* load avg */
1677 t++;
1678 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1679 float avg1, avg2, avg3;
1680 int actproc, totproc, npid, which;
1681 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1682 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1683 if (sscanf(t, "%d", &which) == 1) {
1684 switch (which) {
1685 case 1:
1686 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1687 break;
1688 case 2:
1689 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1690 break;
1691 case 3:
1692 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1693 break;
1694 case 4:
1695 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1696 break;
1697 case 5:
1698 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1699 break;
1703 break;
1704 #endif
1705 case 's': /* Asterisk system name (from asterisk.conf) */
1706 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1707 break;
1708 case 't': /* time */
1709 memset(&tm, 0, sizeof(tm));
1710 time(&ts);
1711 if (localtime_r(&ts, &tm)) {
1712 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1714 break;
1715 case '#': /* process console or remote? */
1716 if (!ast_opt_remote) {
1717 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1718 } else {
1719 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1721 break;
1722 case '%': /* literal % */
1723 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1724 break;
1725 case '\0': /* % is last character - prevent bug */
1726 t--;
1727 break;
1729 while (*p != '\0') {
1730 p++;
1732 t++;
1733 } else {
1734 *p = *t;
1735 p++;
1736 t++;
1739 if (color_used) {
1740 /* Force colors back to normal at end */
1741 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1742 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1743 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1744 } else {
1745 strncat(p, term_code, sizeof(term_code));
1748 } else if (remotehostname)
1749 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1750 else
1751 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1753 return(prompt);
1756 static char **ast_el_strtoarr(char *buf)
1758 char **match_list = NULL, *retstr;
1759 size_t match_list_len;
1760 int matches = 0;
1762 match_list_len = 1;
1763 while ( (retstr = strsep(&buf, " ")) != NULL) {
1765 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1766 break;
1767 if (matches + 1 >= match_list_len) {
1768 match_list_len <<= 1;
1769 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1770 /* TODO: Handle memory allocation failure */
1774 match_list[matches++] = strdup(retstr);
1777 if (!match_list)
1778 return (char **) NULL;
1780 if (matches >= match_list_len) {
1781 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1782 /* TODO: Handle memory allocation failure */
1786 match_list[matches] = (char *) NULL;
1788 return match_list;
1791 static int ast_el_sort_compare(const void *i1, const void *i2)
1793 char *s1, *s2;
1795 s1 = ((char **)i1)[0];
1796 s2 = ((char **)i2)[0];
1798 return strcasecmp(s1, s2);
1801 static int ast_cli_display_match_list(char **matches, int len, int max)
1803 int i, idx, limit, count;
1804 int screenwidth = 0;
1805 int numoutput = 0, numoutputline = 0;
1807 screenwidth = ast_get_termcols(STDOUT_FILENO);
1809 /* find out how many entries can be put on one line, with two spaces between strings */
1810 limit = screenwidth / (max + 2);
1811 if (limit == 0)
1812 limit = 1;
1814 /* how many lines of output */
1815 count = len / limit;
1816 if (count * limit < len)
1817 count++;
1819 idx = 1;
1821 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1823 for (; count > 0; count--) {
1824 numoutputline = 0;
1825 for (i=0; i < limit && matches[idx]; i++, idx++) {
1827 /* Don't print dupes */
1828 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1829 i--;
1830 free(matches[idx]);
1831 matches[idx] = NULL;
1832 continue;
1835 numoutput++;
1836 numoutputline++;
1837 fprintf(stdout, "%-*s ", max, matches[idx]);
1838 free(matches[idx]);
1839 matches[idx] = NULL;
1841 if (numoutputline > 0)
1842 fprintf(stdout, "\n");
1845 return numoutput;
1849 static char *cli_complete(EditLine *el, int ch)
1851 int len = 0;
1852 char *ptr;
1853 int nummatches = 0;
1854 char **matches;
1855 int retval = CC_ERROR;
1856 char buf[2048];
1857 int res;
1859 LineInfo *lf = (LineInfo *)el_line(el);
1861 *(char *)lf->cursor = '\0';
1862 ptr = (char *)lf->cursor;
1863 if (ptr) {
1864 while (ptr > lf->buffer) {
1865 if (isspace(*ptr)) {
1866 ptr++;
1867 break;
1869 ptr--;
1873 len = lf->cursor - ptr;
1875 if (ast_opt_remote) {
1876 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1877 fdprint(ast_consock, buf);
1878 res = read(ast_consock, buf, sizeof(buf));
1879 buf[res] = '\0';
1880 nummatches = atoi(buf);
1882 if (nummatches > 0) {
1883 char *mbuf;
1884 int mlen = 0, maxmbuf = 2048;
1885 /* Start with a 2048 byte buffer */
1886 if (!(mbuf = ast_malloc(maxmbuf)))
1887 return (char *)(CC_ERROR);
1888 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1889 fdprint(ast_consock, buf);
1890 res = 0;
1891 mbuf[0] = '\0';
1892 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1893 if (mlen + 1024 > maxmbuf) {
1894 /* Every step increment buffer 1024 bytes */
1895 maxmbuf += 1024;
1896 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1897 return (char *)(CC_ERROR);
1899 /* Only read 1024 bytes at a time */
1900 res = read(ast_consock, mbuf + mlen, 1024);
1901 if (res > 0)
1902 mlen += res;
1904 mbuf[mlen] = '\0';
1906 matches = ast_el_strtoarr(mbuf);
1907 free(mbuf);
1908 } else
1909 matches = (char **) NULL;
1910 } else {
1911 char **p, *oldbuf=NULL;
1912 nummatches = 0;
1913 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1914 for (p = matches; p && *p; p++) {
1915 if (!oldbuf || strcmp(*p,oldbuf))
1916 nummatches++;
1917 oldbuf = *p;
1921 if (matches) {
1922 int i;
1923 int matches_num, maxlen, match_len;
1925 if (matches[0][0] != '\0') {
1926 el_deletestr(el, (int) len);
1927 el_insertstr(el, matches[0]);
1928 retval = CC_REFRESH;
1931 if (nummatches == 1) {
1932 /* Found an exact match */
1933 el_insertstr(el, " ");
1934 retval = CC_REFRESH;
1935 } else {
1936 /* Must be more than one match */
1937 for (i=1, maxlen=0; matches[i]; i++) {
1938 match_len = strlen(matches[i]);
1939 if (match_len > maxlen)
1940 maxlen = match_len;
1942 matches_num = i - 1;
1943 if (matches_num >1) {
1944 fprintf(stdout, "\n");
1945 ast_cli_display_match_list(matches, nummatches, maxlen);
1946 retval = CC_REDISPLAY;
1947 } else {
1948 el_insertstr(el," ");
1949 retval = CC_REFRESH;
1952 free(matches);
1955 return (char *)(long)retval;
1958 static int ast_el_initialize(void)
1960 HistEvent ev;
1961 char *editor = getenv("AST_EDITOR");
1963 if (el != NULL)
1964 el_end(el);
1965 if (el_hist != NULL)
1966 history_end(el_hist);
1968 el = el_init("asterisk", stdin, stdout, stderr);
1969 el_set(el, EL_PROMPT, cli_prompt);
1971 el_set(el, EL_EDITMODE, 1);
1972 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1973 el_hist = history_init();
1974 if (!el || !el_hist)
1975 return -1;
1977 /* setup history with 100 entries */
1978 history(el_hist, &ev, H_SETSIZE, 100);
1980 el_set(el, EL_HIST, history, el_hist);
1982 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1983 /* Bind <tab> to command completion */
1984 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1985 /* Bind ? to command completion */
1986 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1987 /* Bind ^D to redisplay */
1988 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1990 return 0;
1993 static int ast_el_add_history(char *buf)
1995 HistEvent ev;
1997 if (el_hist == NULL || el == NULL)
1998 ast_el_initialize();
1999 if (strlen(buf) > 256)
2000 return 0;
2001 return (history(el_hist, &ev, H_ENTER, buf));
2004 static int ast_el_write_history(char *filename)
2006 HistEvent ev;
2008 if (el_hist == NULL || el == NULL)
2009 ast_el_initialize();
2011 return (history(el_hist, &ev, H_SAVE, filename));
2014 static int ast_el_read_history(char *filename)
2016 char buf[256];
2017 FILE *f;
2018 int ret = -1;
2020 if (el_hist == NULL || el == NULL)
2021 ast_el_initialize();
2023 if ((f = fopen(filename, "r")) == NULL)
2024 return ret;
2026 while (!feof(f)) {
2027 fgets(buf, sizeof(buf), f);
2028 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2029 continue;
2030 if (ast_all_zeros(buf))
2031 continue;
2032 if ((ret = ast_el_add_history(buf)) == -1)
2033 break;
2035 fclose(f);
2037 return ret;
2040 static void ast_remotecontrol(char * data)
2042 char buf[80];
2043 int res;
2044 char filename[80] = "";
2045 char *hostname;
2046 char *cpid;
2047 char *version;
2048 int pid;
2049 char tmp[80];
2050 char *stringp = NULL;
2052 char *ebuf;
2053 int num = 0;
2055 read(ast_consock, buf, sizeof(buf));
2056 if (data)
2057 write(ast_consock, data, strlen(data) + 1);
2058 stringp = buf;
2059 hostname = strsep(&stringp, "/");
2060 cpid = strsep(&stringp, "/");
2061 version = strsep(&stringp, "\n");
2062 if (!version)
2063 version = "<Version Unknown>";
2064 stringp = hostname;
2065 strsep(&stringp, ".");
2066 if (cpid)
2067 pid = atoi(cpid);
2068 else
2069 pid = -1;
2070 snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
2071 fdprint(ast_consock, tmp);
2072 snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
2073 fdprint(ast_consock, tmp);
2074 if (ast_opt_mute) {
2075 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2076 fdprint(ast_consock, tmp);
2078 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2079 remotehostname = hostname;
2080 if (getenv("HOME"))
2081 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2082 if (el_hist == NULL || el == NULL)
2083 ast_el_initialize();
2085 el_set(el, EL_GETCFN, ast_el_read_char);
2087 if (!ast_strlen_zero(filename))
2088 ast_el_read_history(filename);
2090 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2091 char tempchar;
2092 #ifdef __Darwin__
2093 struct pollfd fds[0];
2094 fds[0].fd = ast_consock;
2095 fds[0].events = POLLIN;
2096 fds[0].revents = 0;
2097 while (poll(fds, 1, 100) > 0) {
2098 ast_el_read_char(el, &tempchar);
2100 #else
2101 while (!ast_el_read_char(el, &tempchar));
2102 #endif
2103 return;
2105 for (;;) {
2106 ebuf = (char *)el_gets(el, &num);
2108 if (!ast_strlen_zero(ebuf)) {
2109 if (ebuf[strlen(ebuf)-1] == '\n')
2110 ebuf[strlen(ebuf)-1] = '\0';
2111 if (!remoteconsolehandler(ebuf)) {
2112 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2113 if (res < 1) {
2114 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2115 break;
2120 printf("\nDisconnected from Asterisk server\n");
2123 static int show_version(void)
2125 printf("Asterisk " ASTERISK_VERSION "\n");
2126 return 0;
2129 static int show_cli_help(void) {
2130 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2131 printf("Usage: asterisk [OPTIONS]\n");
2132 printf("Valid Options:\n");
2133 printf(" -V Display version number and exit\n");
2134 printf(" -C <configfile> Use an alternate configuration file\n");
2135 printf(" -G <group> Run as a group other than the caller\n");
2136 printf(" -U <user> Run as a user other than the caller\n");
2137 printf(" -c Provide console CLI\n");
2138 printf(" -d Enable extra debugging\n");
2139 printf(" -f Do not fork\n");
2140 printf(" -g Dump core in case of a crash\n");
2141 printf(" -h This help screen\n");
2142 printf(" -i Initialize crypto keys at startup\n");
2143 printf(" -I Enable internal timing if Zaptel timer is available\n");
2144 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2145 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2146 printf(" -m Mute the console from debugging and verbose output\n");
2147 printf(" -n Disable console colorization\n");
2148 printf(" -p Run as pseudo-realtime thread\n");
2149 printf(" -q Quiet mode (suppress output)\n");
2150 printf(" -r Connect to Asterisk on this machine\n");
2151 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2152 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2153 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2154 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2155 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2156 printf("\n");
2157 return 0;
2160 static void ast_readconfig(void)
2162 struct ast_config *cfg;
2163 struct ast_variable *v;
2164 char *config = AST_CONFIG_FILE;
2166 if (ast_opt_override_config) {
2167 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2168 if (!cfg)
2169 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2170 } else {
2171 cfg = ast_config_load(config);
2174 /* init with buildtime config */
2175 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2176 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2177 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2178 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2179 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2180 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2181 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2182 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2183 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2184 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2185 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2186 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2187 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2189 /* no asterisk.conf? no problem, use buildtime config! */
2190 if (!cfg) {
2191 return;
2193 v = ast_variable_browse(cfg, "files");
2194 while (v) {
2195 if (!strcasecmp(v->name, "astctlpermissions")) {
2196 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2197 } else if (!strcasecmp(v->name, "astctlowner")) {
2198 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2199 } else if (!strcasecmp(v->name, "astctlgroup")) {
2200 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2201 } else if (!strcasecmp(v->name, "astctl")) {
2202 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2204 v = v->next;
2206 v = ast_variable_browse(cfg, "directories");
2207 while(v) {
2208 if (!strcasecmp(v->name, "astetcdir")) {
2209 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2210 } else if (!strcasecmp(v->name, "astspooldir")) {
2211 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2212 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2213 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2214 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2215 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2216 } else if (!strcasecmp(v->name, "astdatadir")) {
2217 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2218 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2219 } else if (!strcasecmp(v->name, "astlogdir")) {
2220 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2221 } else if (!strcasecmp(v->name, "astagidir")) {
2222 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2223 } else if (!strcasecmp(v->name, "astrundir")) {
2224 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2225 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2226 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2227 } else if (!strcasecmp(v->name, "astmoddir")) {
2228 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2229 } else if (!strcasecmp(v->name, "languageprefix")) {
2230 ast_language_is_prefix = ast_true(v->value);
2232 v = v->next;
2234 v = ast_variable_browse(cfg, "options");
2235 while(v) {
2236 /* verbose level (-v at startup) */
2237 if (!strcasecmp(v->name, "verbose")) {
2238 option_verbose = atoi(v->value);
2239 /* whether or not to force timestamping. (-T at startup) */
2240 } else if (!strcasecmp(v->name, "timestamp")) {
2241 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2242 /* whether or not to support #exec in config files */
2243 } else if (!strcasecmp(v->name, "execincludes")) {
2244 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2245 /* debug level (-d at startup) */
2246 } else if (!strcasecmp(v->name, "debug")) {
2247 option_debug = 0;
2248 if (sscanf(v->value, "%d", &option_debug) != 1) {
2249 option_debug = ast_true(v->value);
2251 /* Disable forking (-f at startup) */
2252 } else if (!strcasecmp(v->name, "nofork")) {
2253 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2254 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2255 } else if (!strcasecmp(v->name, "alwaysfork")) {
2256 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2257 /* Run quietly (-q at startup ) */
2258 } else if (!strcasecmp(v->name, "quiet")) {
2259 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2260 /* Run as console (-c at startup, implies nofork) */
2261 } else if (!strcasecmp(v->name, "console")) {
2262 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2263 /* Run with high priority if the O/S permits (-p at startup) */
2264 } else if (!strcasecmp(v->name, "highpriority")) {
2265 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2266 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2267 } else if (!strcasecmp(v->name, "initcrypto")) {
2268 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2269 /* Disable ANSI colors for console (-c at startup) */
2270 } else if (!strcasecmp(v->name, "nocolor")) {
2271 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2272 /* Disable some usage warnings for picky people :p */
2273 } else if (!strcasecmp(v->name, "dontwarn")) {
2274 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2275 /* Dump core in case of crash (-g) */
2276 } else if (!strcasecmp(v->name, "dumpcore")) {
2277 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2278 /* Cache recorded sound files to another directory during recording */
2279 } else if (!strcasecmp(v->name, "cache_record_files")) {
2280 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2281 /* Specify cache directory */
2282 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2283 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2284 /* Build transcode paths via SLINEAR, instead of directly */
2285 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2286 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2287 /* Transmit SLINEAR silence while a channel is being recorded */
2288 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2289 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2290 /* Enable internal timing */
2291 } else if (!strcasecmp(v->name, "internal_timing")) {
2292 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2293 } else if (!strcasecmp(v->name, "maxcalls")) {
2294 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2295 option_maxcalls = 0;
2297 } else if (!strcasecmp(v->name, "maxload")) {
2298 double test[1];
2300 if (getloadavg(test, 1) == -1) {
2301 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2302 option_maxload = 0.0;
2303 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2304 option_maxload = 0.0;
2306 /* What user to run as */
2307 } else if (!strcasecmp(v->name, "runuser")) {
2308 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2309 /* What group to run as */
2310 } else if (!strcasecmp(v->name, "rungroup")) {
2311 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2312 } else if (!strcasecmp(v->name, "systemname")) {
2313 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2315 v = v->next;
2317 ast_config_destroy(cfg);
2320 int main(int argc, char *argv[])
2322 int c;
2323 char filename[80] = "";
2324 char hostname[MAXHOSTNAMELEN] = "";
2325 char tmp[80];
2326 char * xarg = NULL;
2327 int x;
2328 FILE *f;
2329 sigset_t sigs;
2330 int num;
2331 int is_child_of_nonroot = 0;
2332 char *buf;
2333 char *runuser = NULL, *rungroup = NULL;
2335 /* Remember original args for restart */
2336 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2337 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2338 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2340 for (x=0; x<argc; x++)
2341 _argv[x] = argv[x];
2342 _argv[x] = NULL;
2344 /* if the progname is rasterisk consider it a remote console */
2345 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2346 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2348 if (gethostname(hostname, sizeof(hostname)-1))
2349 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2350 ast_mainpid = getpid();
2351 ast_ulaw_init();
2352 ast_alaw_init();
2353 callerid_init();
2354 ast_builtins_init();
2355 ast_utils_init();
2356 tdd_init();
2357 /* When Asterisk restarts after it has dropped the root privileges,
2358 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2360 if (getenv("ASTERISK_ALREADY_NONROOT"))
2361 is_child_of_nonroot=1;
2362 if (getenv("HOME"))
2363 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2364 /* Check for options */
2365 while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2366 switch (c) {
2367 case 'F':
2368 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2369 break;
2370 case 'd':
2371 option_debug++;
2372 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2373 break;
2374 case 'c':
2375 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2376 break;
2377 case 'f':
2378 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2379 break;
2380 case 'n':
2381 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2382 break;
2383 case 'r':
2384 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2385 break;
2386 case 'R':
2387 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2388 break;
2389 case 'p':
2390 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2391 break;
2392 case 'v':
2393 option_verbose++;
2394 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2395 break;
2396 case 'm':
2397 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2398 break;
2399 case 'M':
2400 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2401 option_maxcalls = 0;
2402 break;
2403 case 'L':
2404 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2405 option_maxload = 0.0;
2406 break;
2407 case 'q':
2408 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2409 break;
2410 case 't':
2411 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2412 break;
2413 case 'T':
2414 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2415 break;
2416 case 'x':
2417 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2418 xarg = optarg;
2419 break;
2420 case 'C':
2421 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2422 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2423 break;
2424 case 'I':
2425 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2426 break;
2427 case 'i':
2428 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2429 break;
2430 case 'g':
2431 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2432 break;
2433 case 'h':
2434 show_cli_help();
2435 exit(0);
2436 case 'V':
2437 show_version();
2438 exit(0);
2439 case 'U':
2440 runuser = optarg;
2441 break;
2442 case 'G':
2443 rungroup = optarg;
2444 break;
2445 case '?':
2446 exit(1);
2450 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2451 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2452 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2455 /* For remote connections, change the name of the remote connection.
2456 * We do this for the benefit of init scripts (which need to know if/when
2457 * the main asterisk process has died yet). */
2458 if (ast_opt_remote) {
2459 strcpy(argv[0], "rasterisk");
2460 for (x = 1; x < argc; x++) {
2461 argv[x] = argv[0] + 10;
2465 if (ast_opt_console && !option_verbose)
2466 ast_verbose("[ Reading Master Configuration ]");
2467 ast_readconfig();
2469 if (ast_opt_dump_core) {
2470 struct rlimit l;
2471 memset(&l, 0, sizeof(l));
2472 l.rlim_cur = RLIM_INFINITY;
2473 l.rlim_max = RLIM_INFINITY;
2474 if (setrlimit(RLIMIT_CORE, &l)) {
2475 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2479 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2480 rungroup = ast_config_AST_RUN_GROUP;
2481 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2482 runuser = ast_config_AST_RUN_USER;
2484 #ifndef __CYGWIN__
2486 if (!is_child_of_nonroot)
2487 ast_set_priority(ast_opt_high_priority);
2489 if (!is_child_of_nonroot && rungroup) {
2490 struct group *gr;
2491 gr = getgrnam(rungroup);
2492 if (!gr) {
2493 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2494 exit(1);
2496 if (setgid(gr->gr_gid)) {
2497 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2498 exit(1);
2500 if (setgroups(0, NULL)) {
2501 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2502 exit(1);
2504 if (option_verbose)
2505 ast_verbose("Running as group '%s'\n", rungroup);
2508 if (!is_child_of_nonroot && runuser) {
2509 struct passwd *pw;
2510 pw = getpwnam(runuser);
2511 if (!pw) {
2512 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2513 exit(1);
2515 if (!rungroup) {
2516 if (setgid(pw->pw_gid)) {
2517 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2518 exit(1);
2520 if (initgroups(pw->pw_name, pw->pw_gid)) {
2521 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2522 exit(1);
2525 if (setuid(pw->pw_uid)) {
2526 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2527 exit(1);
2529 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2530 if (option_verbose)
2531 ast_verbose("Running as user '%s'\n", runuser);
2534 #endif /* __CYGWIN__ */
2536 #ifdef linux
2537 if (geteuid() && ast_opt_dump_core) {
2538 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2539 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2542 #endif
2544 term_init();
2545 printf(term_end());
2546 fflush(stdout);
2548 if (ast_opt_console && !option_verbose)
2549 ast_verbose("[ Initializing Custom Configuration Options ]");
2550 /* custom config setup */
2551 register_config_cli();
2552 read_config_maps();
2554 if (ast_opt_console) {
2555 if (el_hist == NULL || el == NULL)
2556 ast_el_initialize();
2558 if (!ast_strlen_zero(filename))
2559 ast_el_read_history(filename);
2562 if (ast_tryconnect()) {
2563 /* One is already running */
2564 if (ast_opt_remote) {
2565 if (ast_opt_exec) {
2566 ast_remotecontrol(xarg);
2567 quit_handler(0, 0, 0, 0);
2568 exit(0);
2570 printf(term_quit());
2571 ast_register_verbose(console_verboser);
2572 WELCOME_MESSAGE;
2573 ast_remotecontrol(NULL);
2574 quit_handler(0, 0, 0, 0);
2575 exit(0);
2576 } else {
2577 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2578 printf(term_quit());
2579 exit(1);
2581 } else if (ast_opt_remote || ast_opt_exec) {
2582 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2583 printf(term_quit());
2584 exit(1);
2586 /* Blindly write pid file since we couldn't connect */
2587 unlink(ast_config_AST_PID);
2588 f = fopen(ast_config_AST_PID, "w");
2589 if (f) {
2590 fprintf(f, "%ld\n", (long)getpid());
2591 fclose(f);
2592 } else
2593 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2595 if (ast_opt_always_fork || !ast_opt_no_fork) {
2596 daemon(0, 0);
2597 ast_mainpid = getpid();
2598 /* Blindly re-write pid file since we are forking */
2599 unlink(ast_config_AST_PID);
2600 f = fopen(ast_config_AST_PID, "w");
2601 if (f) {
2602 fprintf(f, "%ld\n", (long)ast_mainpid);
2603 fclose(f);
2604 } else
2605 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2608 /* Test recursive mutex locking. */
2609 if (test_for_thread_safety())
2610 ast_verbose("Warning! Asterisk is not thread safe.\n");
2612 ast_makesocket();
2613 sigemptyset(&sigs);
2614 sigaddset(&sigs, SIGHUP);
2615 sigaddset(&sigs, SIGTERM);
2616 sigaddset(&sigs, SIGINT);
2617 sigaddset(&sigs, SIGPIPE);
2618 sigaddset(&sigs, SIGWINCH);
2619 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2620 if (ast_opt_console || option_verbose || ast_opt_remote)
2621 ast_register_verbose(console_verboser);
2622 /* Print a welcome message if desired */
2623 if (option_verbose || ast_opt_console) {
2624 WELCOME_MESSAGE;
2626 if (ast_opt_console && !option_verbose)
2627 ast_verbose("[ Booting...");
2629 signal(SIGURG, urg_handler);
2630 signal(SIGINT, __quit_handler);
2631 signal(SIGTERM, __quit_handler);
2632 signal(SIGHUP, hup_handler);
2633 signal(SIGCHLD, child_handler);
2634 signal(SIGPIPE, SIG_IGN);
2636 /* ensure that the random number generators are seeded with a different value every time
2637 Asterisk is started
2639 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2640 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2642 if (init_logger()) {
2643 printf(term_quit());
2644 exit(1);
2646 if (dnsmgr_init()) {
2647 printf(term_quit());
2648 exit(1);
2650 /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2651 if (load_modules(1)) {
2652 printf(term_quit());
2653 exit(1);
2655 ast_http_init();
2656 ast_channels_init();
2657 if (init_manager()) {
2658 printf(term_quit());
2659 exit(1);
2661 if (ast_cdr_engine_init()) {
2662 printf(term_quit());
2663 exit(1);
2665 if (ast_device_state_engine_init()) {
2666 printf(term_quit());
2667 exit(1);
2669 ast_rtp_init();
2670 ast_udptl_init();
2671 if (ast_image_init()) {
2672 printf(term_quit());
2673 exit(1);
2675 if (ast_file_init()) {
2676 printf(term_quit());
2677 exit(1);
2679 if (load_pbx()) {
2680 printf(term_quit());
2681 exit(1);
2683 if (load_modules(0)) {
2684 printf(term_quit());
2685 exit(1);
2687 if (init_framer()) {
2688 printf(term_quit());
2689 exit(1);
2691 if (astdb_init()) {
2692 printf(term_quit());
2693 exit(1);
2695 if (ast_enum_init()) {
2696 printf(term_quit());
2697 exit(1);
2700 dnsmgr_start_refresh();
2702 #if 0
2703 /* This should no longer be necessary */
2704 /* sync cust config and reload some internals in case a custom config handler binded to them */
2705 read_ast_cust_config();
2706 reload_logger(0);
2707 reload_manager();
2708 ast_enum_reload();
2709 ast_rtp_reload();
2710 #endif
2712 /* We might have the option of showing a console, but for now just
2713 do nothing... */
2714 if (ast_opt_console && !option_verbose)
2715 ast_verbose(" ]\n");
2716 if (option_verbose || ast_opt_console)
2717 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2718 if (ast_opt_no_fork)
2719 consolethread = pthread_self();
2720 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2721 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2722 #ifdef __AST_DEBUG_MALLOC
2723 __ast_mm_init();
2724 #endif
2725 time(&ast_startuptime);
2726 ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2727 if (ast_opt_console) {
2728 /* Console stuff now... */
2729 /* Register our quit function */
2730 char title[256];
2731 set_icon("Asterisk");
2732 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2733 set_title(title);
2735 for (;;) {
2736 buf = (char *)el_gets(el, &num);
2737 if (buf) {
2738 if (buf[strlen(buf)-1] == '\n')
2739 buf[strlen(buf)-1] = '\0';
2741 consolehandler((char *)buf);
2742 } else {
2743 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2744 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2745 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2746 int fd;
2747 fd = open("/dev/null", O_RDWR);
2748 if (fd > -1) {
2749 dup2(fd, STDOUT_FILENO);
2750 dup2(fd, STDIN_FILENO);
2751 } else
2752 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2753 break;
2759 /* Do nothing */
2760 for(;;) { /* apparently needed for the MACos */
2761 struct pollfd p = { -1 /* no descriptor */, 0, 0 };
2762 poll(&p, 0, -1);
2764 return 0;