2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
22 * \mainpage Asterisk -- An Open Source Telephony Toolkit
24 * \par Developer Documentation for Asterisk
25 * This is the main developer documentation for Asterisk. It is
26 * generated by running "make progdocs".
27 * \par Additional documentation
29 * \arg \ref ConfigFiles
31 * \section copyright Copyright and author
33 * Copyright (C) 1999 - 2006, Digium, Inc.
34 * Asterisk is a trade mark registered by Digium, Inc.
36 * \author Mark Spencer <markster@digium.com>
37 * Also see \ref AstCREDITS
39 * \section license License
40 * See http://www.asterisk.org for more information about
41 * the Asterisk project. Please do not directly contact
42 * any of the maintainers of this project for assistance;
43 * the project provides a web site, mailing lists and IRC
44 * channels for your use.
46 * This program is free software, distributed under the terms of
47 * the GNU General Public License Version 2. See the LICENSE file
48 * at the top of the source tree.
50 * \verbinclude LICENSE
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
64 #undef sched_setscheduler
73 #include <sys/socket.h>
79 #include <sys/resource.h>
83 #if defined(HAVE_SYSINFO)
84 #include <sys/sysinfo.h>
87 #include <sys/prctl.h>
89 #include <sys/capability.h>
94 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
97 int daemon(int, int); /* defined in libresolv of all places */
101 #include "asterisk/logger.h"
102 #include "asterisk/options.h"
103 #include "asterisk/cli.h"
104 #include "asterisk/channel.h"
105 #include "asterisk/ulaw.h"
106 #include "asterisk/alaw.h"
107 #include "asterisk/callerid.h"
108 #include "asterisk/image.h"
109 #include "asterisk/tdd.h"
110 #include "asterisk/term.h"
111 #include "asterisk/manager.h"
112 #include "asterisk/cdr.h"
113 #include "asterisk/pbx.h"
114 #include "asterisk/enum.h"
115 #include "asterisk/rtp.h"
116 #include "asterisk/http.h"
117 #include "asterisk/udptl.h"
118 #include "asterisk/app.h"
119 #include "asterisk/lock.h"
120 #include "asterisk/utils.h"
121 #include "asterisk/file.h"
122 #include "asterisk/io.h"
123 #include "asterisk/lock.h"
124 #include "editline/histedit.h"
125 #include "asterisk/config.h"
126 #include "asterisk/version.h"
127 #include "asterisk/linkedlists.h"
128 #include "asterisk/devicestate.h"
129 #include "asterisk/module.h"
131 #include "asterisk/doxyref.h" /* Doxygen documentation */
133 #include "../defaults.h"
136 #define AF_LOCAL AF_UNIX
137 #define PF_LOCAL PF_UNIX
140 #define AST_MAX_CONNECTS 128
143 /*! \brief Welcome message when starting a CLI interface */
144 #define WELCOME_MESSAGE \
145 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2007 Digium, Inc. and others.\n" \
146 "Created by Mark Spencer <markster@digium.com>\n" \
147 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
148 "This is free software, with components licensed under the GNU General Public\n" \
149 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
150 "certain conditions. Type 'core show license' for details.\n" \
151 "=========================================================================\n" \
152 "NOTE: This is a development version of Asterisk, and should not be used in\n" \
153 "production installations.\n");
155 /*! \defgroup main_options Main Configuration Options
156 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
157 * \arg \ref Config_ast "asterisk.conf"
158 * \note Some of them can be changed in the CLI
162 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
164 int option_verbose; /*!< Verbosity level */
165 int option_debug; /*!< Debug level */
166 double option_maxload; /*!< Max load avg on system */
167 int option_maxcalls; /*!< Max number of active calls */
168 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
169 #if defined(HAVE_SYSINFO)
170 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
175 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
177 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
178 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
181 int fd; /*!< File descriptor */
182 int p[2]; /*!< Pipe */
183 pthread_t t; /*!< Thread of handler */
184 int mute; /*!< Is the console muted for logs */
189 AST_RWLIST_ENTRY(ast_atexit) list;
192 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
194 struct timeval ast_startuptime;
195 struct timeval ast_lastreloadtime;
197 static History *el_hist;
199 static char *remotehostname;
201 struct console consoles[AST_MAX_CONNECTS];
203 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
205 static int ast_el_add_history(char *);
206 static int ast_el_read_history(char *);
207 static int ast_el_write_history(char *);
209 char ast_config_AST_CONFIG_DIR[PATH_MAX];
210 char ast_config_AST_CONFIG_FILE[PATH_MAX];
211 char ast_config_AST_MODULE_DIR[PATH_MAX];
212 char ast_config_AST_SPOOL_DIR[PATH_MAX];
213 char ast_config_AST_MONITOR_DIR[PATH_MAX];
214 char ast_config_AST_VAR_DIR[PATH_MAX];
215 char ast_config_AST_DATA_DIR[PATH_MAX];
216 char ast_config_AST_LOG_DIR[PATH_MAX];
217 char ast_config_AST_AGI_DIR[PATH_MAX];
218 char ast_config_AST_DB[PATH_MAX];
219 char ast_config_AST_KEY_DIR[PATH_MAX];
220 char ast_config_AST_PID[PATH_MAX];
221 char ast_config_AST_SOCKET[PATH_MAX];
222 char ast_config_AST_RUN_DIR[PATH_MAX];
223 char ast_config_AST_RUN_USER[PATH_MAX];
224 char ast_config_AST_RUN_GROUP[PATH_MAX];
225 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
226 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
227 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
228 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
229 char ast_config_AST_SYSTEM_NAME[20] = "";
231 extern const char *ast_build_hostname;
232 extern const char *ast_build_kernel;
233 extern const char *ast_build_machine;
234 extern const char *ast_build_os;
235 extern const char *ast_build_date;
236 extern const char *ast_build_user;
238 static char *_argv[256];
239 static int shuttingdown;
240 static int restartnow;
241 static pthread_t consolethread = AST_PTHREADT_NULL;
243 static char randompool[256];
245 static int sig_alert_pipe[2] = { -1, -1 };
247 unsigned int need_reload:1;
248 unsigned int need_quit:1;
251 #if !defined(LOW_MEMORY)
252 struct file_version {
253 AST_RWLIST_ENTRY(file_version) list;
258 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
260 void ast_register_file_version(const char *file, const char *version)
262 struct file_version *new;
264 size_t version_length;
266 work = ast_strdupa(version);
267 work = ast_strip(ast_strip_quoted(work, "$", "$"));
268 version_length = strlen(work) + 1;
270 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
274 new->version = (char *) new + sizeof(*new);
275 memcpy(new->version, work, version_length);
276 AST_RWLIST_WRLOCK(&file_versions);
277 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
278 AST_RWLIST_UNLOCK(&file_versions);
281 void ast_unregister_file_version(const char *file)
283 struct file_version *find;
285 AST_RWLIST_WRLOCK(&file_versions);
286 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
287 if (!strcasecmp(find->file, file)) {
288 AST_RWLIST_REMOVE_CURRENT(&file_versions, list);
292 AST_RWLIST_TRAVERSE_SAFE_END;
293 AST_RWLIST_UNLOCK(&file_versions);
299 struct thread_list_t {
300 AST_RWLIST_ENTRY(thread_list_t) list;
305 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
307 static const char show_threads_help[] =
308 "Usage: core show threads\n"
309 " List threads currently active in the system.\n";
311 void ast_register_thread(char *name)
313 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
317 new->id = pthread_self();
318 new->name = name; /* steal the allocated memory for the thread name */
319 AST_RWLIST_WRLOCK(&thread_list);
320 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
321 AST_RWLIST_UNLOCK(&thread_list);
324 void ast_unregister_thread(void *id)
326 struct thread_list_t *x;
328 AST_RWLIST_WRLOCK(&thread_list);
329 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
330 if ((void *) x->id == id) {
331 AST_RWLIST_REMOVE_CURRENT(&thread_list, list);
335 AST_RWLIST_TRAVERSE_SAFE_END;
336 AST_RWLIST_UNLOCK(&thread_list);
343 /*! \brief Give an overview of core settings */
344 static int handle_show_settings(int fd, int argc, char *argv[])
349 ast_cli(fd, "\nPBX Core settings\n");
350 ast_cli(fd, "-----------------\n");
351 ast_cli(fd, " Version: %s\n", "" ASTERISK_VERSION "" );
353 ast_cli(fd, " Max. calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
355 ast_cli(fd, " Max. calls: Not set\n");
357 ast_cli(fd, " Max. open file handles: %d\n", option_maxfiles);
359 ast_cli(fd, " Max. open file handles: Not set\n");
360 ast_cli(fd, " Verbosity: %d\n", option_verbose);
361 ast_cli(fd, " Debug level: %d\n", option_debug);
362 ast_cli(fd, " Max load avg: %lf\n", option_maxload);
363 #if defined(HAVE_SYSINFO)
364 ast_cli(fd, " Min Free Memory: %ld MB\n", option_minmemfree);
366 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
367 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
368 ast_cli(fd, " Startup time: %s\n", buf);
370 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
371 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
372 ast_cli(fd, " Last reload time: %s\n", buf);
374 ast_cli(fd, " System: %s/%s built by %s on %s %s\n", ast_build_os, ast_build_kernel, ast_build_user, ast_build_machine, ast_build_date);
375 ast_cli(fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
376 ast_cli(fd, " Default language: %s\n", defaultlanguage);
377 ast_cli(fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
378 ast_cli(fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
379 ast_cli(fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
380 ast_cli(fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
381 ast_cli(fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
382 ast_cli(fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
384 ast_cli(fd, "\n* Subsystems\n");
385 ast_cli(fd, " -------------\n");
386 ast_cli(fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
387 ast_cli(fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
388 ast_cli(fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
389 ast_cli(fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
391 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
393 ast_cli(fd, "\n* Directories\n");
394 ast_cli(fd, " -------------\n");
395 ast_cli(fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
396 ast_cli(fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
397 ast_cli(fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
398 ast_cli(fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
399 ast_cli(fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
404 static int handle_show_threads(int fd, int argc, char *argv[])
407 struct thread_list_t *cur;
409 AST_RWLIST_RDLOCK(&thread_list);
410 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
411 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
414 AST_RWLIST_UNLOCK(&thread_list);
415 ast_cli(fd, "%d threads listed.\n", count);
419 #if defined(HAVE_SYSINFO)
420 static const char show_sysinfo_help[] =
421 "Usage: core show sysinfo\n"
422 " List current system information.\n";
424 /*! \brief Give an overview of system statistics */
425 static int handle_show_sysinfo(int fd, int argc, char *argv[])
427 struct sysinfo sys_info;
429 if (sysinfo(&sys_info)) {
430 ast_cli(fd, "FAILED to retrieve system information\n\n");
433 ast_cli(fd, "\nSystem Statistics\n");
434 ast_cli(fd, "-----------------\n");
435 ast_cli(fd, " System Uptime: %ld hours\n", sys_info.uptime/3600);
436 ast_cli(fd, " Total RAM: %ld KiB\n", (sys_info.totalram / sys_info.mem_unit)/1024);
437 ast_cli(fd, " Free RAM: %ld KiB\n", (sys_info.freeram / sys_info.mem_unit)/1024);
438 ast_cli(fd, " Buffer RAM: %ld KiB\n", (sys_info.bufferram / sys_info.mem_unit)/1024);
439 ast_cli(fd, " Total Swap Space: %ld KiB\n", (sys_info.totalswap / sys_info.mem_unit)/1024);
440 ast_cli(fd, " Free Swap Space: %ld KiB\n\n", (sys_info.freeswap / sys_info.mem_unit)/1024);
441 ast_cli(fd, " Number of Processes: %d \n\n", sys_info.procs);
446 struct profile_entry {
448 uint64_t scale; /* if non-zero, values are scaled by this */
454 struct profile_data {
457 struct profile_entry e[0];
460 static struct profile_data *prof_data;
462 /*! \brief allocates a counter with a given name and scale.
463 * \return Returns the identifier of the counter.
465 int ast_add_profile(const char *name, uint64_t scale)
467 int l = sizeof(struct profile_data);
468 int n = 10; /* default entries */
470 if (prof_data == NULL) {
471 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
472 if (prof_data == NULL)
474 prof_data->entries = 0;
475 prof_data->max_size = n;
477 if (prof_data->entries >= prof_data->max_size) {
479 n = prof_data->max_size + 20;
480 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
484 prof_data->max_size = n;
486 n = prof_data->entries++;
487 prof_data->e[n].name = ast_strdup(name);
488 prof_data->e[n].value = 0;
489 prof_data->e[n].events = 0;
490 prof_data->e[n].mark = 0;
491 prof_data->e[n].scale = scale;
495 int64_t ast_profile(int i, int64_t delta)
497 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
499 if (prof_data->e[i].scale > 1)
500 delta /= prof_data->e[i].scale;
501 prof_data->e[i].value += delta;
502 prof_data->e[i].events++;
503 return prof_data->e[i].value;
506 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
507 #if defined(__FreeBSD__)
508 #include <machine/cpufunc.h>
510 static __inline uint64_t
515 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
519 #else /* supply a dummy function on other platforms */
520 static __inline uint64_t
527 int64_t ast_mark(int i, int startstop)
529 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
532 prof_data->e[i].mark = rdtsc();
534 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
535 if (prof_data->e[i].scale > 1)
536 prof_data->e[i].mark /= prof_data->e[i].scale;
537 prof_data->e[i].value += prof_data->e[i].mark;
538 prof_data->e[i].events++;
540 return prof_data->e[i].mark;
543 static int handle_show_profile(int fd, int argc, char *argv[])
548 if (prof_data == NULL)
552 max = prof_data->entries;
553 if (argc > 3) { /* specific entries */
554 if (isdigit(argv[3][0])) {
556 if (argc == 5 && strcmp(argv[4], "-"))
561 if (max > prof_data->entries)
562 max = prof_data->entries;
563 if (!strcmp(argv[1], "clear")) {
564 for (i= min; i < max; i++) {
565 if (!search || strstr(prof_data->e[i].name, search)) {
566 prof_data->e[i].value = 0;
567 prof_data->e[i].events = 0;
572 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
573 prof_data->entries, prof_data->max_size);
574 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
575 "Value", "Average", "Name");
576 for (i = min; i < max; i++) {
577 struct profile_entry *e = &prof_data->e[i];
578 if (!search || strstr(prof_data->e[i].name, search))
579 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
582 (long)e->events, (long long)e->value,
583 (long long)(e->events ? e->value / e->events : e->value),
589 static const char show_version_files_help[] =
590 "Usage: core show file version [like <pattern>]\n"
591 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
592 " Optional regular expression pattern is used to filter the file list.\n";
594 /*! \brief CLI command to list module versions */
595 static int handle_show_version_files(int fd, int argc, char *argv[])
597 #define FORMAT "%-25.25s %-40.40s\n"
598 struct file_version *iterator;
606 if (!strcasecmp(argv[4], "like")) {
607 if (regcomp(®exbuf, argv[5], REG_EXTENDED | REG_NOSUB))
608 return RESULT_SHOWUSAGE;
611 return RESULT_SHOWUSAGE;
619 return RESULT_SHOWUSAGE;
622 ast_cli(fd, FORMAT, "File", "Revision");
623 ast_cli(fd, FORMAT, "----", "--------");
624 AST_RWLIST_RDLOCK(&file_versions);
625 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
626 if (havename && strcasecmp(iterator->file, argv[4]))
629 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
632 ast_cli(fd, FORMAT, iterator->file, iterator->version);
637 AST_RWLIST_UNLOCK(&file_versions);
639 ast_cli(fd, "%d files listed.\n", count_files);
645 return RESULT_SUCCESS;
649 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
651 struct file_version *find;
654 int matchlen = strlen(word);
659 AST_RWLIST_RDLOCK(&file_versions);
660 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
661 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
662 ret = ast_strdup(find->file);
666 AST_RWLIST_UNLOCK(&file_versions);
670 #endif /* ! LOW_MEMORY */
672 int ast_register_atexit(void (*func)(void))
675 struct ast_atexit *ae;
676 ast_unregister_atexit(func);
677 AST_RWLIST_WRLOCK(&atexits);
678 if ((ae = ast_calloc(1, sizeof(*ae)))) {
679 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
683 AST_RWLIST_UNLOCK(&atexits);
687 void ast_unregister_atexit(void (*func)(void))
689 struct ast_atexit *ae;
690 AST_RWLIST_WRLOCK(&atexits);
691 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
692 if (ae->func == func) {
693 AST_RWLIST_REMOVE_CURRENT(&atexits, list);
697 AST_RWLIST_TRAVERSE_SAFE_END
698 AST_RWLIST_UNLOCK(&atexits);
701 static int fdprint(int fd, const char *s)
703 return write(fd, s, strlen(s) + 1);
706 /*! \brief NULL handler so we can collect the child exit status */
707 static void null_sig_handler(int signal)
712 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
713 /*! \brief Keep track of how many threads are currently trying to wait*() on
715 static unsigned int safe_system_level = 0;
716 static void *safe_system_prev_handler;
718 void ast_replace_sigchld(void)
722 ast_mutex_lock(&safe_system_lock);
723 level = safe_system_level++;
725 /* only replace the handler if it has not already been done */
727 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
729 ast_mutex_unlock(&safe_system_lock);
732 void ast_unreplace_sigchld(void)
736 ast_mutex_lock(&safe_system_lock);
737 level = --safe_system_level;
739 /* only restore the handler if we are the last one */
741 signal(SIGCHLD, safe_system_prev_handler);
743 ast_mutex_unlock(&safe_system_lock);
746 int ast_safe_system(const char *s)
749 #ifdef HAVE_WORKING_FORK
753 struct rusage rusage;
756 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
757 ast_replace_sigchld();
759 #ifdef HAVE_WORKING_FORK
766 #ifdef HAVE_WORKING_FORK
767 if (ast_opt_high_priority)
769 /* Close file descriptors and launch system command */
770 for (x = STDERR_FILENO + 1; x < 4096; x++)
773 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
775 } else if (pid > 0) {
777 res = wait4(pid, &status, 0, &rusage);
779 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
781 } else if (errno != EINTR)
785 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
789 ast_unreplace_sigchld();
798 * \brief mute or unmute a console from logging
800 void ast_console_toggle_mute(int fd) {
802 for (x = 0;x < AST_MAX_CONNECTS; x++) {
803 if (fd == consoles[x].fd) {
804 if (consoles[x].mute) {
805 consoles[x].mute = 0;
806 ast_cli(fd, "Console is not muted anymore.\n");
808 consoles[x].mute = 1;
809 ast_cli(fd, "Console is muted.\n");
814 ast_cli(fd, "Couldn't find remote console.\n");
818 * \brief log the string to all attached console clients
820 static void ast_network_puts_mutable(const char *string)
823 for (x = 0;x < AST_MAX_CONNECTS; x++) {
824 if (consoles[x].mute)
826 if (consoles[x].fd > -1)
827 fdprint(consoles[x].p[1], string);
832 * \brief log the string to the console, and all attached
835 void ast_console_puts_mutable(const char *string)
837 fputs(string, stdout);
839 ast_network_puts_mutable(string);
843 * \brief write the string to all attached console clients
845 static void ast_network_puts(const char *string)
848 for (x=0; x < AST_MAX_CONNECTS; x++) {
849 if (consoles[x].fd > -1)
850 fdprint(consoles[x].p[1], string);
855 * write the string to the console, and all attached
858 void ast_console_puts(const char *string)
860 fputs(string, stdout);
862 ast_network_puts(string);
865 static void network_verboser(const char *s)
867 ast_network_puts_mutable(s);
870 static pthread_t lthread;
872 static void *netconsole(void *vconsole)
874 struct console *con = vconsole;
875 char hostname[MAXHOSTNAMELEN] = "";
878 struct pollfd fds[2];
880 if (gethostname(hostname, sizeof(hostname)-1))
881 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
882 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
883 fdprint(con->fd, tmp);
886 fds[0].events = POLLIN;
888 fds[1].fd = con->p[0];
889 fds[1].events = POLLIN;
892 res = poll(fds, 2, -1);
895 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
898 if (fds[0].revents) {
899 res = read(con->fd, tmp, sizeof(tmp));
904 ast_cli_command(con->fd, tmp);
906 if (fds[1].revents) {
907 res = read(con->p[0], tmp, sizeof(tmp));
909 ast_log(LOG_ERROR, "read returned %d\n", res);
912 res = write(con->fd, tmp, res);
917 if (option_verbose > 2)
918 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
927 static void *listener(void *unused)
929 struct sockaddr_un sunaddr;
934 struct pollfd fds[1];
938 fds[0].fd = ast_socket;
939 fds[0].events = POLLIN;
940 s = poll(fds, 1, -1);
941 pthread_testcancel();
944 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
947 len = sizeof(sunaddr);
948 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
951 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
953 for (x = 0; x < AST_MAX_CONNECTS; x++) {
954 if (consoles[x].fd < 0) {
955 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
956 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
958 fdprint(s, "Server failed to create pipe\n");
962 flags = fcntl(consoles[x].p[1], F_GETFL);
963 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
965 consoles[x].mute = ast_opt_mute;
966 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
967 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
968 close(consoles[x].p[0]);
969 close(consoles[x].p[1]);
971 fdprint(s, "Server failed to spawn thread\n");
977 if (x >= AST_MAX_CONNECTS) {
978 fdprint(s, "No more connections allowed\n");
979 ast_log(LOG_WARNING, "No more connections allowed\n");
981 } else if (consoles[x].fd > -1) {
982 if (option_verbose > 2)
983 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
990 static int ast_makesocket(void)
992 struct sockaddr_un sunaddr;
998 for (x = 0; x < AST_MAX_CONNECTS; x++)
1000 unlink(ast_config_AST_SOCKET);
1001 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1002 if (ast_socket < 0) {
1003 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1006 memset(&sunaddr, 0, sizeof(sunaddr));
1007 sunaddr.sun_family = AF_LOCAL;
1008 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1009 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1011 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1016 res = listen(ast_socket, 2);
1018 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1023 ast_register_verbose(network_verboser);
1024 ast_pthread_create_background(<hread, NULL, listener, NULL);
1026 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1028 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1029 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1034 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1036 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1037 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1042 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1043 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1045 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1048 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
1050 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1051 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1057 static int ast_tryconnect(void)
1059 struct sockaddr_un sunaddr;
1061 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1062 if (ast_consock < 0) {
1063 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1066 memset(&sunaddr, 0, sizeof(sunaddr));
1067 sunaddr.sun_family = AF_LOCAL;
1068 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1069 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1078 /*! \brief Urgent handler
1080 Called by soft_hangup to interrupt the poll, read, or other
1081 system call. We don't actually need to do anything though.
1082 Remember: Cannot EVER ast_log from within a signal handler
1084 static void urg_handler(int num)
1086 signal(num, urg_handler);
1090 static void hup_handler(int num)
1093 if (option_verbose > 1)
1094 printf("Received HUP signal -- Reloading configs\n");
1096 execvp(_argv[0], _argv);
1097 sig_flags.need_reload = 1;
1098 if (sig_alert_pipe[1] != -1)
1099 write(sig_alert_pipe[1], &a, sizeof(a));
1100 signal(num, hup_handler);
1103 static void child_handler(int sig)
1105 /* Must not ever ast_log or ast_verbose within signal handler */
1109 * Reap all dead children -- not just one
1111 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1113 if (n == 0 && option_debug)
1114 printf("Huh? Child handler, but nobody there?\n");
1115 signal(sig, child_handler);
1118 /*! \brief Set maximum open files */
1119 static void set_ulimit(int value)
1121 struct rlimit l = {0, 0};
1124 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1131 if (setrlimit(RLIMIT_NOFILE, &l)) {
1132 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1136 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1141 /*! \brief Set an X-term or screen title */
1142 static void set_title(char *text)
1144 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1145 fprintf(stdout, "\033]2;%s\007", text);
1148 static void set_icon(char *text)
1150 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1151 fprintf(stdout, "\033]1;%s\007", text);
1154 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1155 else. If your PBX has heavy activity on it, this is a good thing. */
1156 int ast_set_priority(int pri)
1158 struct sched_param sched;
1159 memset(&sched, 0, sizeof(sched));
1162 sched.sched_priority = 10;
1163 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1164 ast_log(LOG_WARNING, "Unable to set high priority\n");
1168 ast_verbose("Set to realtime thread\n");
1170 sched.sched_priority = 0;
1171 /* According to the manpage, these parameters can never fail. */
1172 sched_setscheduler(0, SCHED_OTHER, &sched);
1176 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1177 ast_log(LOG_WARNING, "Unable to set high priority\n");
1181 ast_verbose("Set to high priority\n");
1183 /* According to the manpage, these parameters can never fail. */
1184 setpriority(PRIO_PROCESS, 0, 0);
1190 static void ast_run_atexits(void)
1192 struct ast_atexit *ae;
1193 AST_RWLIST_RDLOCK(&atexits);
1194 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1198 AST_RWLIST_UNLOCK(&atexits);
1201 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1203 char filename[80] = "";
1206 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1207 ast_cdr_engine_term();
1211 /* Begin shutdown routine, hanging up active channels */
1212 ast_begin_shutdown(1);
1213 if (option_verbose && ast_opt_console)
1214 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1218 /* Wait up to 15 seconds for all channels to go away */
1221 if (!ast_active_channels())
1225 /* Sleep 1/10 of a second */
1230 ast_begin_shutdown(0);
1231 if (option_verbose && ast_opt_console)
1232 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1234 if (!ast_active_channels())
1242 if (!shuttingdown) {
1243 if (option_verbose && ast_opt_console)
1244 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1249 ast_module_shutdown();
1251 if (ast_opt_console || ast_opt_remote) {
1253 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1254 if (!ast_strlen_zero(filename))
1255 ast_el_write_history(filename);
1258 if (el_hist != NULL)
1259 history_end(el_hist);
1262 ast_verbose("Executing last minute cleanups\n");
1264 /* Called on exit */
1265 if (option_verbose && ast_opt_console)
1266 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1267 ast_debug(1, "Asterisk ending (%d).\n", num);
1268 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1269 if (ast_socket > -1) {
1270 pthread_cancel(lthread);
1273 unlink(ast_config_AST_SOCKET);
1275 if (ast_consock > -1)
1277 if (!ast_opt_remote)
1278 unlink(ast_config_AST_PID);
1279 printf(term_quit());
1281 if (option_verbose || ast_opt_console)
1282 ast_verbose("Preparing for Asterisk restart...\n");
1283 /* Mark all FD's for closing on exec */
1284 for (x=3; x < 32768; x++) {
1285 fcntl(x, F_SETFD, FD_CLOEXEC);
1287 if (option_verbose || ast_opt_console)
1288 ast_verbose("Asterisk is now restarting...\n");
1294 /* If there is a consolethread running send it a SIGHUP
1295 so it can execvp, otherwise we can do it ourselves */
1296 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1297 pthread_kill(consolethread, SIGHUP);
1298 /* Give the signal handler some time to complete */
1301 execvp(_argv[0], _argv);
1310 static void __quit_handler(int num)
1313 sig_flags.need_quit = 1;
1314 if (sig_alert_pipe[1] != -1)
1315 write(sig_alert_pipe[1], &a, sizeof(a));
1316 /* There is no need to restore the signal handler here, since the app
1317 * is going to exit */
1320 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1323 if (!strncmp(s, cmp, strlen(cmp))) {
1324 c = s + strlen(cmp);
1325 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1331 static void console_verboser(const char *s)
1334 const char *c = NULL;
1336 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1337 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1338 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1339 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1347 /* Wake up a poll()ing console */
1348 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1349 pthread_kill(consolethread, SIGURG);
1352 static int ast_all_zeros(char *s)
1362 static void consolehandler(char *s)
1367 /* Called when readline data is available */
1368 if (!ast_all_zeros(s))
1369 ast_el_add_history(s);
1370 /* The real handler for bang */
1373 ast_safe_system(s+1);
1375 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1377 ast_cli_command(STDOUT_FILENO, s);
1380 static int remoteconsolehandler(char *s)
1384 /* Called when readline data is available */
1385 if (!ast_all_zeros(s))
1386 ast_el_add_history(s);
1387 /* The real handler for bang */
1390 ast_safe_system(s+1);
1392 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1395 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1396 (s[4] == '\0' || isspace(s[4]))) {
1397 quit_handler(0, 0, 0, 0);
1404 static const char abort_halt_help[] =
1405 "Usage: abort shutdown\n"
1406 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1407 " call operations.\n";
1409 static const char shutdown_now_help[] =
1411 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1413 static const char shutdown_gracefully_help[] =
1414 "Usage: stop gracefully\n"
1415 " Causes Asterisk to not accept new calls, and exit when all\n"
1416 " active calls have terminated normally.\n";
1418 static const char shutdown_when_convenient_help[] =
1419 "Usage: stop when convenient\n"
1420 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1422 static const char restart_now_help[] =
1423 "Usage: restart now\n"
1424 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1427 static const char restart_gracefully_help[] =
1428 "Usage: restart gracefully\n"
1429 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1430 " restart when all active calls have ended.\n";
1432 static const char restart_when_convenient_help[] =
1433 "Usage: restart when convenient\n"
1434 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1436 static const char bang_help[] =
1437 "Usage: !<command>\n"
1438 " Executes a given shell command\n";
1440 static const char show_warranty_help[] =
1441 "Usage: core show warranty\n"
1442 " Shows the warranty (if any) for this copy of Asterisk.\n";
1444 static const char show_license_help[] =
1445 "Usage: core show license\n"
1446 " Shows the license(s) for this copy of Asterisk.\n";
1448 static const char version_help[] =
1449 "Usage: core show version\n"
1450 " Shows Asterisk version information.\n";
1452 static int handle_version(int fd, int argc, char *argv[])
1455 return RESULT_SHOWUSAGE;
1456 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1457 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1458 ast_build_machine, ast_build_os, ast_build_date);
1459 return RESULT_SUCCESS;
1463 static int handle_quit(int fd, int argc, char *argv[])
1466 return RESULT_SHOWUSAGE;
1467 quit_handler(0, 0, 1, 0);
1468 return RESULT_SUCCESS;
1472 static int handle_shutdown_now(int fd, int argc, char *argv[])
1475 return RESULT_SHOWUSAGE;
1476 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1477 return RESULT_SUCCESS;
1480 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1483 return RESULT_SHOWUSAGE;
1484 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1485 return RESULT_SUCCESS;
1488 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1491 return RESULT_SHOWUSAGE;
1492 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1493 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1494 return RESULT_SUCCESS;
1497 static int handle_restart_now(int fd, int argc, char *argv[])
1500 return RESULT_SHOWUSAGE;
1501 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1502 return RESULT_SUCCESS;
1505 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1508 return RESULT_SHOWUSAGE;
1509 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1510 return RESULT_SUCCESS;
1513 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1516 return RESULT_SHOWUSAGE;
1517 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1518 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1519 return RESULT_SUCCESS;
1522 static int handle_abort_halt(int fd, int argc, char *argv[])
1525 return RESULT_SHOWUSAGE;
1526 ast_cancel_shutdown();
1528 return RESULT_SUCCESS;
1531 static int handle_bang(int fd, int argc, char *argv[])
1533 return RESULT_SUCCESS;
1535 static const char warranty_lines[] = {
1539 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
1540 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
1541 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
1542 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
1543 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
1544 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
1545 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
1546 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
1547 "REPAIR OR CORRECTION.\n"
1549 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
1550 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
1551 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
1552 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
1553 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
1554 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
1555 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
1556 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
1557 "POSSIBILITY OF SUCH DAMAGES.\n"
1560 static int show_warranty(int fd, int argc, char *argv[])
1562 ast_cli(fd, warranty_lines);
1564 return RESULT_SUCCESS;
1567 static const char license_lines[] = {
1569 "This program is free software; you can redistribute it and/or modify\n"
1570 "it under the terms of the GNU General Public License version 2 as\n"
1571 "published by the Free Software Foundation.\n"
1573 "This program also contains components licensed under other licenses.\n"
1576 "This program is distributed in the hope that it will be useful,\n"
1577 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1578 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1579 "GNU General Public License for more details.\n"
1581 "You should have received a copy of the GNU General Public License\n"
1582 "along with this program; if not, write to the Free Software\n"
1583 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
1586 static int show_license(int fd, int argc, char *argv[])
1588 ast_cli(fd, license_lines);
1590 return RESULT_SUCCESS;
1593 #define ASTERISK_PROMPT "*CLI> "
1595 #define ASTERISK_PROMPT2 "%s*CLI> "
1597 static struct ast_cli_entry cli_asterisk[] = {
1598 { { "abort", "halt", NULL },
1599 handle_abort_halt, "Cancel a running halt",
1602 { { "stop", "now", NULL },
1603 handle_shutdown_now, "Shut down Asterisk immediately",
1604 shutdown_now_help },
1606 { { "stop", "gracefully", NULL },
1607 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1608 shutdown_gracefully_help },
1610 { { "stop", "when", "convenient", NULL },
1611 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1612 shutdown_when_convenient_help },
1614 { { "restart", "now", NULL },
1615 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1617 { { "restart", "gracefully", NULL },
1618 handle_restart_gracefully, "Restart Asterisk gracefully",
1619 restart_gracefully_help },
1621 { { "restart", "when", "convenient", NULL },
1622 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1623 restart_when_convenient_help },
1625 { { "core", "show", "warranty", NULL },
1626 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1627 show_warranty_help },
1629 { { "core", "show", "license", NULL },
1630 show_license, "Show the license(s) for this copy of Asterisk",
1631 show_license_help },
1633 { { "core", "show", "version", NULL },
1634 handle_version, "Display version info",
1638 handle_bang, "Execute a shell command",
1641 #if !defined(LOW_MEMORY)
1642 { { "core", "show", "file", "version", NULL },
1643 handle_show_version_files, "List versions of files used to build Asterisk",
1644 show_version_files_help, complete_show_version_files },
1646 { { "core", "show", "threads", NULL },
1647 handle_show_threads, "Show running threads",
1648 show_threads_help },
1650 #if defined(HAVE_SYSINFO)
1651 { { "core", "show", "sysinfo", NULL },
1652 handle_show_sysinfo, "Show System Information",
1653 show_sysinfo_help },
1656 { { "core", "show", "profile", NULL },
1657 handle_show_profile, "Display profiling info",
1660 { { "core", "show", "settings", NULL },
1661 handle_show_settings, "Show some core settings",
1664 { { "core", "clear", "profile", NULL },
1665 handle_show_profile, "Clear profiling info",
1667 #endif /* ! LOW_MEMORY */
1670 static int ast_el_read_char(EditLine *el, char *cp)
1674 struct pollfd fds[2];
1681 fds[0].fd = ast_consock;
1682 fds[0].events = POLLIN;
1683 if (!ast_opt_exec) {
1684 fds[1].fd = STDIN_FILENO;
1685 fds[1].events = POLLIN;
1688 res = poll(fds, max, -1);
1692 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1696 if (!ast_opt_exec && fds[1].revents) {
1697 num_read = read(STDIN_FILENO, cp, 1);
1703 if (fds[0].revents) {
1704 res = read(ast_consock, buf, sizeof(buf) - 1);
1705 /* if the remote side disappears exit */
1707 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1708 if (!ast_opt_reconnect) {
1709 quit_handler(0, 0, 0, 0);
1712 int reconnects_per_second = 20;
1713 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1714 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1715 if (ast_tryconnect()) {
1716 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1717 printf(term_quit());
1721 usleep(1000000 / reconnects_per_second);
1723 if (tries >= 30 * reconnects_per_second) {
1724 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1725 quit_handler(0, 0, 0, 0);
1732 if (!ast_opt_exec && !lastpos)
1733 write(STDOUT_FILENO, "\r", 1);
1734 write(STDOUT_FILENO, buf, res);
1735 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1747 static char *cli_prompt(EditLine *el)
1749 static char prompt[200];
1754 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1755 char *t = pfmt, *p = prompt;
1756 memset(prompt, 0, sizeof(prompt));
1757 while (*t != '\0' && *p < sizeof(prompt)) {
1759 char hostname[MAXHOSTNAMELEN]="";
1761 struct timeval ts = ast_tvnow();
1762 struct ast_tm tm = { 0, };
1766 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1770 case 'C': /* color */
1772 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1773 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1775 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1776 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1780 /* If the color has been reset correctly, then there's no need to reset it later */
1781 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
1783 case 'd': /* date */
1784 if (ast_localtime(&ts, &tm, NULL))
1785 ast_strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1787 case 'h': /* hostname */
1788 if (!gethostname(hostname, sizeof(hostname) - 1))
1789 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1791 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1793 case 'H': /* short hostname */
1794 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1795 for (i = 0; i < sizeof(hostname); i++) {
1796 if (hostname[i] == '.') {
1801 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1803 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1806 case 'l': /* load avg */
1808 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1809 float avg1, avg2, avg3;
1810 int actproc, totproc, npid, which;
1811 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1812 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1813 if (sscanf(t, "%d", &which) == 1) {
1816 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1819 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1822 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1825 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1828 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1835 case 's': /* Asterisk system name (from asterisk.conf) */
1836 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1838 case 't': /* time */
1839 if (ast_localtime(&ts, &tm, NULL))
1840 ast_strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1842 case '#': /* process console or remote? */
1843 if (!ast_opt_remote)
1844 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1846 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1848 case '%': /* literal % */
1849 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1851 case '\0': /* % is last character - prevent bug */
1865 /* Force colors back to normal at end */
1866 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1867 if (strlen(term_code) > sizeof(prompt) - strlen(prompt))
1868 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1870 strncat(p, term_code, sizeof(term_code));
1872 } else if (remotehostname)
1873 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1875 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1880 static char **ast_el_strtoarr(char *buf)
1882 char **match_list = NULL, *retstr;
1883 size_t match_list_len;
1887 while ( (retstr = strsep(&buf, " ")) != NULL) {
1889 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1891 if (matches + 1 >= match_list_len) {
1892 match_list_len <<= 1;
1893 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1894 /* TODO: Handle memory allocation failure */
1898 match_list[matches++] = ast_strdup(retstr);
1902 return (char **) NULL;
1904 if (matches >= match_list_len) {
1905 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1906 /* TODO: Handle memory allocation failure */
1910 match_list[matches] = (char *) NULL;
1915 static int ast_el_sort_compare(const void *i1, const void *i2)
1919 s1 = ((char **)i1)[0];
1920 s2 = ((char **)i2)[0];
1922 return strcasecmp(s1, s2);
1925 static int ast_cli_display_match_list(char **matches, int len, int max)
1927 int i, idx, limit, count;
1928 int screenwidth = 0;
1929 int numoutput = 0, numoutputline = 0;
1931 screenwidth = ast_get_termcols(STDOUT_FILENO);
1933 /* find out how many entries can be put on one line, with two spaces between strings */
1934 limit = screenwidth / (max + 2);
1938 /* how many lines of output */
1939 count = len / limit;
1940 if (count * limit < len)
1945 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1947 for (; count > 0; count--) {
1949 for (i=0; i < limit && matches[idx]; i++, idx++) {
1951 /* Don't print dupes */
1952 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1954 ast_free(matches[idx]);
1955 matches[idx] = NULL;
1961 fprintf(stdout, "%-*s ", max, matches[idx]);
1962 ast_free(matches[idx]);
1963 matches[idx] = NULL;
1965 if (numoutputline > 0)
1966 fprintf(stdout, "\n");
1973 static char *cli_complete(EditLine *el, int ch)
1979 int retval = CC_ERROR;
1983 LineInfo *lf = (LineInfo *)el_line(el);
1985 *(char *)lf->cursor = '\0';
1986 ptr = (char *)lf->cursor;
1988 while (ptr > lf->buffer) {
1989 if (isspace(*ptr)) {
1997 len = lf->cursor - ptr;
1999 if (ast_opt_remote) {
2000 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2001 fdprint(ast_consock, buf);
2002 res = read(ast_consock, buf, sizeof(buf));
2004 nummatches = atoi(buf);
2006 if (nummatches > 0) {
2008 int mlen = 0, maxmbuf = 2048;
2009 /* Start with a 2048 byte buffer */
2010 if (!(mbuf = ast_malloc(maxmbuf)))
2011 return (char *)(CC_ERROR);
2012 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2013 fdprint(ast_consock, buf);
2016 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2017 if (mlen + 1024 > maxmbuf) {
2018 /* Every step increment buffer 1024 bytes */
2020 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2021 return (char *)(CC_ERROR);
2023 /* Only read 1024 bytes at a time */
2024 res = read(ast_consock, mbuf + mlen, 1024);
2030 matches = ast_el_strtoarr(mbuf);
2033 matches = (char **) NULL;
2035 char **p, *oldbuf=NULL;
2037 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2038 for (p = matches; p && *p; p++) {
2039 if (!oldbuf || strcmp(*p,oldbuf))
2047 int matches_num, maxlen, match_len;
2049 if (matches[0][0] != '\0') {
2050 el_deletestr(el, (int) len);
2051 el_insertstr(el, matches[0]);
2052 retval = CC_REFRESH;
2055 if (nummatches == 1) {
2056 /* Found an exact match */
2057 el_insertstr(el, " ");
2058 retval = CC_REFRESH;
2060 /* Must be more than one match */
2061 for (i=1, maxlen=0; matches[i]; i++) {
2062 match_len = strlen(matches[i]);
2063 if (match_len > maxlen)
2066 matches_num = i - 1;
2067 if (matches_num >1) {
2068 fprintf(stdout, "\n");
2069 ast_cli_display_match_list(matches, nummatches, maxlen);
2070 retval = CC_REDISPLAY;
2072 el_insertstr(el," ");
2073 retval = CC_REFRESH;
2076 for (i = 0; matches[i]; i++)
2077 ast_free(matches[i]);
2081 return (char *)(long)retval;
2084 static int ast_el_initialize(void)
2087 char *editor = getenv("AST_EDITOR");
2091 if (el_hist != NULL)
2092 history_end(el_hist);
2094 el = el_init("asterisk", stdin, stdout, stderr);
2095 el_set(el, EL_PROMPT, cli_prompt);
2097 el_set(el, EL_EDITMODE, 1);
2098 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2099 el_hist = history_init();
2100 if (!el || !el_hist)
2103 /* setup history with 100 entries */
2104 history(el_hist, &ev, H_SETSIZE, 100);
2106 el_set(el, EL_HIST, history, el_hist);
2108 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2109 /* Bind <tab> to command completion */
2110 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2111 /* Bind ? to command completion */
2112 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2113 /* Bind ^D to redisplay */
2114 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2119 static int ast_el_add_history(char *buf)
2123 if (el_hist == NULL || el == NULL)
2124 ast_el_initialize();
2125 if (strlen(buf) > 256)
2127 return (history(el_hist, &ev, H_ENTER, buf));
2130 static int ast_el_write_history(char *filename)
2134 if (el_hist == NULL || el == NULL)
2135 ast_el_initialize();
2137 return (history(el_hist, &ev, H_SAVE, filename));
2140 static int ast_el_read_history(char *filename)
2146 if (el_hist == NULL || el == NULL)
2147 ast_el_initialize();
2149 if ((f = fopen(filename, "r")) == NULL)
2153 fgets(buf, sizeof(buf), f);
2154 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2156 if (ast_all_zeros(buf))
2158 if ((ret = ast_el_add_history(buf)) == -1)
2166 static void ast_remotecontrol(char * data)
2170 char filename[80] = "";
2176 char *stringp = NULL;
2181 read(ast_consock, buf, sizeof(buf));
2183 write(ast_consock, data, strlen(data) + 1);
2185 hostname = strsep(&stringp, "/");
2186 cpid = strsep(&stringp, "/");
2187 version = strsep(&stringp, "\n");
2189 version = "<Version Unknown>";
2191 strsep(&stringp, ".");
2196 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2197 fdprint(ast_consock, tmp);
2198 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2199 fdprint(ast_consock, tmp);
2201 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2202 fdprint(ast_consock, tmp);
2204 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2205 remotehostname = hostname;
2207 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2208 if (el_hist == NULL || el == NULL)
2209 ast_el_initialize();
2211 el_set(el, EL_GETCFN, ast_el_read_char);
2213 if (!ast_strlen_zero(filename))
2214 ast_el_read_history(filename);
2216 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2219 fds.fd = ast_consock;
2220 fds.events = POLLIN;
2222 while (poll(&fds, 1, 100) > 0)
2223 ast_el_read_char(el, &tempchar);
2227 ebuf = (char *)el_gets(el, &num);
2229 if (!ebuf && write(1, "", 1) < 0)
2232 if (!ast_strlen_zero(ebuf)) {
2233 if (ebuf[strlen(ebuf)-1] == '\n')
2234 ebuf[strlen(ebuf)-1] = '\0';
2235 if (!remoteconsolehandler(ebuf)) {
2236 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2238 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2244 printf("\nDisconnected from Asterisk server\n");
2247 static int show_version(void)
2249 printf("Asterisk " ASTERISK_VERSION "\n");
2253 static int show_cli_help(void) {
2254 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2007, Digium, Inc. and others.\n");
2255 printf("Usage: asterisk [OPTIONS]\n");
2256 printf("Valid Options:\n");
2257 printf(" -V Display version number and exit\n");
2258 printf(" -C <configfile> Use an alternate configuration file\n");
2259 printf(" -G <group> Run as a group other than the caller\n");
2260 printf(" -U <user> Run as a user other than the caller\n");
2261 printf(" -c Provide console CLI\n");
2262 printf(" -d Enable extra debugging\n");
2263 #if HAVE_WORKING_FORK
2264 printf(" -f Do not fork\n");
2265 printf(" -F Always fork\n");
2267 printf(" -g Dump core in case of a crash\n");
2268 printf(" -h This help screen\n");
2269 printf(" -i Initialize crypto keys at startup\n");
2270 printf(" -I Enable internal timing if Zaptel timer is available\n");
2271 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2272 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2273 printf(" -m Mute the console from debugging and verbose output\n");
2274 printf(" -n Disable console colorization\n");
2275 printf(" -p Run as pseudo-realtime thread\n");
2276 printf(" -q Quiet mode (suppress output)\n");
2277 printf(" -r Connect to Asterisk on this machine\n");
2278 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2279 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2280 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2281 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2282 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2287 static void ast_readconfig(void)
2289 struct ast_config *cfg;
2290 struct ast_variable *v;
2291 char *config = AST_CONFIG_FILE;
2292 char hostname[MAXHOSTNAMELEN] = "";
2293 struct ast_flags config_flags = { 0 };
2295 if (ast_opt_override_config) {
2296 cfg = ast_config_load(ast_config_AST_CONFIG_FILE, config_flags);
2298 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2300 cfg = ast_config_load(config, config_flags);
2302 /* init with buildtime config */
2303 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2304 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2305 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2306 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2307 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2308 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2309 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2310 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2311 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2312 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2313 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2314 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2315 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2317 /* no asterisk.conf? no problem, use buildtime config! */
2322 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2323 if (!strcasecmp(v->name, "astctlpermissions"))
2324 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2325 else if (!strcasecmp(v->name, "astctlowner"))
2326 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2327 else if (!strcasecmp(v->name, "astctlgroup"))
2328 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2329 else if (!strcasecmp(v->name, "astctl"))
2330 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2333 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2334 if (!strcasecmp(v->name, "astetcdir")) {
2335 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2336 } else if (!strcasecmp(v->name, "astspooldir")) {
2337 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2338 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2339 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2340 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2341 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2342 } else if (!strcasecmp(v->name, "astdatadir")) {
2343 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2344 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2345 } else if (!strcasecmp(v->name, "astlogdir")) {
2346 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2347 } else if (!strcasecmp(v->name, "astagidir")) {
2348 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2349 } else if (!strcasecmp(v->name, "astrundir")) {
2350 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2351 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2352 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2353 } else if (!strcasecmp(v->name, "astmoddir")) {
2354 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2358 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2359 /* verbose level (-v at startup) */
2360 if (!strcasecmp(v->name, "verbose")) {
2361 option_verbose = atoi(v->value);
2362 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2363 } else if (!strcasecmp(v->name, "timestamp")) {
2364 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2365 /* whether or not to support #exec in config files */
2366 } else if (!strcasecmp(v->name, "execincludes")) {
2367 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2368 /* debug level (-d at startup) */
2369 } else if (!strcasecmp(v->name, "debug")) {
2371 if (sscanf(v->value, "%d", &option_debug) != 1) {
2372 option_debug = ast_true(v->value);
2374 #if HAVE_WORKING_FORK
2375 /* Disable forking (-f at startup) */
2376 } else if (!strcasecmp(v->name, "nofork")) {
2377 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2378 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2379 } else if (!strcasecmp(v->name, "alwaysfork")) {
2380 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2382 /* Run quietly (-q at startup ) */
2383 } else if (!strcasecmp(v->name, "quiet")) {
2384 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2385 /* Run as console (-c at startup, implies nofork) */
2386 } else if (!strcasecmp(v->name, "console")) {
2387 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2388 /* Run with high priority if the O/S permits (-p at startup) */
2389 } else if (!strcasecmp(v->name, "highpriority")) {
2390 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2391 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2392 } else if (!strcasecmp(v->name, "initcrypto")) {
2393 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2394 /* Disable ANSI colors for console (-c at startup) */
2395 } else if (!strcasecmp(v->name, "nocolor")) {
2396 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2397 /* Disable some usage warnings for picky people :p */
2398 } else if (!strcasecmp(v->name, "dontwarn")) {
2399 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2400 /* Dump core in case of crash (-g) */
2401 } else if (!strcasecmp(v->name, "dumpcore")) {
2402 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2403 /* Cache recorded sound files to another directory during recording */
2404 } else if (!strcasecmp(v->name, "cache_record_files")) {
2405 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2406 /* Specify cache directory */
2407 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2408 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2409 /* Build transcode paths via SLINEAR, instead of directly */
2410 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2411 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2412 /* Transmit SLINEAR silence while a channel is being recorded */
2413 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2414 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2415 /* Enable internal timing */
2416 } else if (!strcasecmp(v->name, "internal_timing")) {
2417 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2418 } else if (!strcasecmp(v->name, "maxcalls")) {
2419 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2420 option_maxcalls = 0;
2422 } else if (!strcasecmp(v->name, "maxload")) {
2425 if (getloadavg(test, 1) == -1) {
2426 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2427 option_maxload = 0.0;
2428 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2429 option_maxload = 0.0;
2431 /* Set the maximum amount of open files */
2432 } else if (!strcasecmp(v->name, "maxfiles")) {
2433 option_maxfiles = atoi(v->value);
2434 set_ulimit(option_maxfiles);
2435 /* What user to run as */
2436 } else if (!strcasecmp(v->name, "runuser")) {
2437 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2438 /* What group to run as */
2439 } else if (!strcasecmp(v->name, "rungroup")) {
2440 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2441 } else if (!strcasecmp(v->name, "systemname")) {
2442 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2443 } else if (!strcasecmp(v->name, "autosystemname")) {
2444 if (ast_true(v->value)) {
2445 if (!gethostname(hostname, sizeof(hostname) - 1))
2446 ast_copy_string(ast_config_AST_SYSTEM_NAME, hostname, sizeof(ast_config_AST_SYSTEM_NAME));
2448 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2449 ast_copy_string(ast_config_AST_SYSTEM_NAME, "localhost", sizeof(ast_config_AST_SYSTEM_NAME));
2451 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2454 } else if (!strcasecmp(v->name, "languageprefix")) {
2455 ast_language_is_prefix = ast_true(v->value);
2456 } else if (!strcasecmp(v->name, "lockmode")) {
2457 if (!strcasecmp(v->value, "lockfile")) {
2458 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2459 } else if (!strcasecmp(v->value, "flock")) {
2460 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
2462 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
2463 "defaulting to 'lockfile'\n", v->value);
2464 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2466 #if defined(HAVE_SYSINFO)
2467 } else if (!strcasecmp(v->name, "minmemfree")) {
2468 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
2469 * if the amount of free memory falls below this watermark */
2470 if ((sscanf(v->value, "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2471 option_minmemfree = 0;
2476 ast_config_destroy(cfg);
2479 static void *monitor_sig_flags(void *unused)
2482 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2485 if (sig_flags.need_reload) {
2486 sig_flags.need_reload = 0;
2487 ast_module_reload(NULL);
2489 if (sig_flags.need_quit) {
2490 sig_flags.need_quit = 0;
2491 quit_handler(0, 0, 1, 0);
2493 read(sig_alert_pipe[0], &a, sizeof(a));
2499 int main(int argc, char *argv[])
2502 char filename[80] = "";
2503 char hostname[MAXHOSTNAMELEN] = "";
2510 int is_child_of_nonroot = 0;
2512 char *runuser = NULL, *rungroup = NULL;
2514 /* Remember original args for restart */
2515 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2516 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2517 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2519 for (x=0; x<argc; x++)
2523 /* if the progname is rasterisk consider it a remote console */
2524 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2525 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2527 if (gethostname(hostname, sizeof(hostname)-1))
2528 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2529 ast_mainpid = getpid();
2533 ast_builtins_init();
2537 /* When Asterisk restarts after it has dropped the root privileges,
2538 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2540 if (getenv("ASTERISK_ALREADY_NONROOT"))
2541 is_child_of_nonroot=1;
2543 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2544 /* Check for options */
2545 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:")) != -1) {
2547 #if defined(HAVE_SYSINFO)
2549 if ((sscanf(&optarg[1], "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2550 option_minmemfree = 0;
2554 #if HAVE_WORKING_FORK
2556 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2559 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2564 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2567 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2570 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2573 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2576 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2579 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2583 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2586 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2589 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2590 option_maxcalls = 0;
2593 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2594 option_maxload = 0.0;
2597 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2600 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2603 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2606 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2610 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2611 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2614 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2617 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2620 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2639 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2640 ast_register_verbose(console_verboser);
2644 if (ast_opt_console && !option_verbose)
2645 ast_verbose("[ Booting...\n");
2647 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2648 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2649 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2652 /* For remote connections, change the name of the remote connection.
2653 * We do this for the benefit of init scripts (which need to know if/when
2654 * the main asterisk process has died yet). */
2655 if (ast_opt_remote) {
2656 strcpy(argv[0], "rasterisk");
2657 for (x = 1; x < argc; x++) {
2658 argv[x] = argv[0] + 10;
2662 if (ast_opt_console && !option_verbose)
2663 ast_verbose("[ Reading Master Configuration ]\n");
2666 if (!ast_language_is_prefix && !ast_opt_remote)
2667 ast_log(LOG_WARNING, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n");
2669 if (ast_opt_dump_core) {
2671 memset(&l, 0, sizeof(l));
2672 l.rlim_cur = RLIM_INFINITY;
2673 l.rlim_max = RLIM_INFINITY;
2674 if (setrlimit(RLIMIT_CORE, &l)) {
2675 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2679 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2680 rungroup = ast_config_AST_RUN_GROUP;
2681 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2682 runuser = ast_config_AST_RUN_USER;
2686 if (!is_child_of_nonroot)
2687 ast_set_priority(ast_opt_high_priority);
2689 if (!is_child_of_nonroot && rungroup) {
2691 gr = getgrnam(rungroup);
2693 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2696 if (setgid(gr->gr_gid)) {
2697 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2700 if (setgroups(0, NULL)) {
2701 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2705 ast_verbose("Running as group '%s'\n", rungroup);
2708 if (!is_child_of_nonroot && runuser) {
2711 #endif /* HAVE_CAP */
2713 pw = getpwnam(runuser);
2715 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2719 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
2720 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
2723 #endif /* HAVE_CAP */
2725 if (setgid(pw->pw_gid)) {
2726 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2729 if (initgroups(pw->pw_name, pw->pw_gid)) {
2730 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2734 if (setuid(pw->pw_uid)) {
2735 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2738 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2740 ast_verbose("Running as user '%s'\n", runuser);
2745 cap = cap_from_text("cap_net_admin=ep");
2747 if (cap_set_proc(cap))
2748 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
2751 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
2753 #endif /* HAVE_CAP */
2756 #endif /* __CYGWIN__ */
2759 if (geteuid() && ast_opt_dump_core) {
2760 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2761 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2770 if (ast_opt_console && !option_verbose)
2771 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2772 /* custom config setup */
2773 register_config_cli();
2776 if (ast_opt_console) {
2777 if (el_hist == NULL || el == NULL)
2778 ast_el_initialize();
2780 if (!ast_strlen_zero(filename))
2781 ast_el_read_history(filename);
2784 if (ast_tryconnect()) {
2785 /* One is already running */
2786 if (ast_opt_remote) {
2788 ast_remotecontrol(xarg);
2789 quit_handler(0, 0, 0, 0);
2792 printf(term_quit());
2793 ast_remotecontrol(NULL);
2794 quit_handler(0, 0, 0, 0);
2797 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2798 printf(term_quit());
2801 } else if (ast_opt_remote || ast_opt_exec) {
2802 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2803 printf(term_quit());
2806 /* Blindly write pid file since we couldn't connect */
2807 unlink(ast_config_AST_PID);
2808 f = fopen(ast_config_AST_PID, "w");
2810 fprintf(f, "%ld\n", (long)getpid());
2813 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2815 #if HAVE_WORKING_FORK
2816 if (ast_opt_always_fork || !ast_opt_no_fork) {
2818 ast_mainpid = getpid();
2819 /* Blindly re-write pid file since we are forking */
2820 unlink(ast_config_AST_PID);
2821 f = fopen(ast_config_AST_PID, "w");
2823 fprintf(f, "%ld\n", (long)ast_mainpid);
2826 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2830 /* Test recursive mutex locking. */
2831 if (test_for_thread_safety())
2832 ast_verbose("Warning! Asterisk is not thread safe.\n");
2836 sigaddset(&sigs, SIGHUP);
2837 sigaddset(&sigs, SIGTERM);
2838 sigaddset(&sigs, SIGINT);
2839 sigaddset(&sigs, SIGPIPE);
2840 sigaddset(&sigs, SIGWINCH);
2841 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2842 signal(SIGURG, urg_handler);
2843 signal(SIGINT, __quit_handler);
2844 signal(SIGTERM, __quit_handler);
2845 signal(SIGHUP, hup_handler);
2846 signal(SIGCHLD, child_handler);
2847 signal(SIGPIPE, SIG_IGN);
2849 /* ensure that the random number generators are seeded with a different value every time
2852 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2853 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2855 if (init_logger()) { /* Start logging subsystem */
2856 printf(term_quit());
2860 threadstorage_init();
2862 if (load_modules(1)) { /* Load modules, pre-load only */
2863 printf(term_quit());
2867 if (dnsmgr_init()) { /* Initialize the DNS manager */
2868 printf(term_quit());
2872 ast_http_init(); /* Start the HTTP server, if needed */
2874 ast_channels_init();
2876 if (init_manager()) {
2877 printf(term_quit());
2881 if (ast_cdr_engine_init()) {
2882 printf(term_quit());
2886 if (ast_device_state_engine_init()) {
2887 printf(term_quit());
2895 if (ast_image_init()) {
2896 printf(term_quit());
2900 if (ast_file_init()) {
2901 printf(term_quit());
2906 printf(term_quit());
2910 if (init_framer()) {
2911 printf(term_quit());
2916 printf(term_quit());
2920 if (ast_enum_init()) {
2921 printf(term_quit());
2925 if (load_modules(0)) {
2926 printf(term_quit());
2930 dnsmgr_start_refresh();
2932 /* We might have the option of showing a console, but for now just
2934 if (ast_opt_console && !option_verbose)
2935 ast_verbose(" ]\n");
2936 if (option_verbose || ast_opt_console)
2937 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2938 if (ast_opt_no_fork)
2939 consolethread = pthread_self();
2941 if (pipe(sig_alert_pipe))
2942 sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
2944 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2945 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2947 #ifdef __AST_DEBUG_MALLOC
2951 ast_startuptime = ast_tvnow();
2952 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
2954 if (ast_opt_console) {
2955 /* Console stuff now... */
2956 /* Register our quit function */
2958 pthread_t dont_care;
2960 ast_pthread_create_detached(&dont_care, NULL, monitor_sig_flags, NULL);
2962 set_icon("Asterisk");
2963 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2967 buf = (char *)el_gets(el, &num);
2969 if (!buf && write(1, "", 1) < 0)
2973 if (buf[strlen(buf)-1] == '\n')
2974 buf[strlen(buf)-1] = '\0';
2976 consolehandler((char *)buf);
2977 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2978 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
2979 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2981 fd = open("/dev/null", O_RDWR);
2983 dup2(fd, STDOUT_FILENO);
2984 dup2(fd, STDIN_FILENO);
2986 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2992 monitor_sig_flags(NULL);