2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2008, 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 -- The Open Source Telephony Project
24 * \par Developer Documentation for Asterisk
26 * This is the main developer documentation for Asterisk. It is
27 * generated by running "make progdocs" from the Asterisk source tree.
29 * In addition to the information available on the Asterisk source code,
30 * please see the appendices for information on coding guidelines,
31 * release management, commit policies, and more.
33 * \arg \ref AsteriskArchitecture
35 * \par Additional documentation
38 * \arg \ref ConfigFiles
40 * \section copyright Copyright and Author
42 * Copyright (C) 1999 - 2009, Digium, Inc.
43 * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
44 * of <a href="http://www.digium.com">Digium, Inc</a>.
46 * \author Mark Spencer <markster@digium.com>
47 * Also see \ref AstCREDITS
49 * See http://www.asterisk.org for more information about
50 * the Asterisk project. Please do not directly contact
51 * any of the maintainers of this project for assistance;
52 * the project provides a web site, mailing lists, and IRC
53 * channels for your use.
57 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
58 of PBX core functions and CLI interface.
64 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
66 #include "asterisk/_private.h"
68 #undef sched_setscheduler
77 #include <sys/resource.h>
81 #if defined(HAVE_SYSINFO)
82 #include <sys/sysinfo.h>
83 #elif defined(HAVE_SYSCTL)
84 #include <sys/param.h>
85 #include <sys/sysctl.h>
86 #if !defined(__OpenBSD__)
87 #include <sys/vmmeter.h>
88 #if defined(__FreeBSD__)
89 #include <vm/vm_param.h>
92 #if defined(HAVE_SWAPCTL)
99 int daemon(int, int); /* defined in libresolv of all places */
100 #include <sys/loadavg.h>
104 #include <sys/prctl.h>
106 #include <sys/capability.h>
107 #endif /* HAVE_CAP */
110 #include "asterisk/paths.h" /* we define here the variables so better agree on the prototype */
111 #include "asterisk/network.h"
112 #include "asterisk/cli.h"
113 #include "asterisk/channel.h"
114 #include "asterisk/features.h"
115 #include "asterisk/ulaw.h"
116 #include "asterisk/alaw.h"
117 #include "asterisk/callerid.h"
118 #include "asterisk/image.h"
119 #include "asterisk/tdd.h"
120 #include "asterisk/term.h"
121 #include "asterisk/manager.h"
122 #include "asterisk/cdr.h"
123 #include "asterisk/cel.h"
124 #include "asterisk/pbx.h"
125 #include "asterisk/enum.h"
126 #include "asterisk/http.h"
127 #include "asterisk/udptl.h"
128 #include "asterisk/app.h"
129 #include "asterisk/lock.h"
130 #include "asterisk/utils.h"
131 #include "asterisk/file.h"
132 #include "asterisk/io.h"
133 #include "editline/histedit.h"
134 #include "asterisk/config.h"
135 #include "asterisk/ast_version.h"
136 #include "asterisk/linkedlists.h"
137 #include "asterisk/devicestate.h"
138 #include "asterisk/module.h"
139 #include "asterisk/dsp.h"
140 #include "asterisk/buildinfo.h"
141 #include "asterisk/xmldoc.h"
142 #include "asterisk/poll-compat.h"
144 #include "../defaults.h"
147 #define AF_LOCAL AF_UNIX
148 #define PF_LOCAL PF_UNIX
151 #define AST_MAX_CONNECTS 128
154 /*! \brief Welcome message when starting a CLI interface */
155 #define WELCOME_MESSAGE \
156 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2009 Digium, Inc. and others.\n" \
157 "Created by Mark Spencer <markster@digium.com>\n" \
158 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
159 "This is free software, with components licensed under the GNU General Public\n" \
160 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
161 "certain conditions. Type 'core show license' for details.\n" \
162 "=========================================================================\n", ast_get_version()) \
164 /*! \defgroup main_options Main Configuration Options
165 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
166 * \arg \ref Config_ast "asterisk.conf"
167 * \note Some of them can be changed in the CLI
171 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
172 struct ast_flags ast_compat = { 0 };
174 int option_verbose; /*!< Verbosity level */
175 int option_debug; /*!< Debug level */
176 double option_maxload; /*!< Max load avg on system */
177 int option_maxcalls; /*!< Max number of active calls */
178 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
179 #if defined(HAVE_SYSINFO)
180 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
185 struct ast_eid ast_eid_default;
187 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
188 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
190 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
191 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
194 int fd; /*!< File descriptor */
195 int p[2]; /*!< Pipe */
196 pthread_t t; /*!< Thread of handler */
197 int mute; /*!< Is the console muted for logs */
198 int uid; /*!< Remote user ID. */
199 int gid; /*!< Remote group ID. */
200 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
205 AST_RWLIST_ENTRY(ast_atexit) list;
208 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
210 struct timeval ast_startuptime;
211 struct timeval ast_lastreloadtime;
213 static History *el_hist;
215 static char *remotehostname;
217 struct console consoles[AST_MAX_CONNECTS];
219 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
221 static int ast_el_add_history(char *);
222 static int ast_el_read_history(char *);
223 static int ast_el_write_history(char *);
226 char config_dir[PATH_MAX];
227 char module_dir[PATH_MAX];
228 char spool_dir[PATH_MAX];
229 char monitor_dir[PATH_MAX];
230 char var_dir[PATH_MAX];
231 char data_dir[PATH_MAX];
232 char log_dir[PATH_MAX];
233 char agi_dir[PATH_MAX];
234 char run_dir[PATH_MAX];
235 char key_dir[PATH_MAX];
237 char config_file[PATH_MAX];
238 char db_path[PATH_MAX];
239 char pid_path[PATH_MAX];
240 char socket_path[PATH_MAX];
241 char run_user[PATH_MAX];
242 char run_group[PATH_MAX];
243 char system_name[128];
246 static struct _cfg_paths cfg_paths;
248 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
249 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
250 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
251 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
252 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
253 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
254 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
255 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
256 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
257 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
258 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
260 const char *ast_config_AST_DB = cfg_paths.db_path;
261 const char *ast_config_AST_PID = cfg_paths.pid_path;
262 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
263 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
264 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
265 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
267 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
268 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
269 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
270 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
272 static char *_argv[256];
273 static int shuttingdown;
274 static int restartnow;
275 static pthread_t consolethread = AST_PTHREADT_NULL;
276 static int canary_pid = 0;
277 static char canary_filename[128];
278 static int canary_pipe = -1;
280 static char randompool[256];
282 static int sig_alert_pipe[2] = { -1, -1 };
284 unsigned int need_reload:1;
285 unsigned int need_quit:1;
288 #if !defined(LOW_MEMORY)
289 struct file_version {
290 AST_RWLIST_ENTRY(file_version) list;
295 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
297 void ast_register_file_version(const char *file, const char *version)
299 struct file_version *new;
301 size_t version_length;
303 work = ast_strdupa(version);
304 work = ast_strip(ast_strip_quoted(work, "$", "$"));
305 version_length = strlen(work) + 1;
307 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
311 new->version = (char *) new + sizeof(*new);
312 memcpy(new->version, work, version_length);
313 AST_RWLIST_WRLOCK(&file_versions);
314 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
315 AST_RWLIST_UNLOCK(&file_versions);
318 void ast_unregister_file_version(const char *file)
320 struct file_version *find;
322 AST_RWLIST_WRLOCK(&file_versions);
323 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
324 if (!strcasecmp(find->file, file)) {
325 AST_RWLIST_REMOVE_CURRENT(list);
329 AST_RWLIST_TRAVERSE_SAFE_END;
330 AST_RWLIST_UNLOCK(&file_versions);
336 char *ast_complete_source_filename(const char *partial, int n)
338 struct file_version *find;
339 size_t len = strlen(partial);
343 AST_RWLIST_RDLOCK(&file_versions);
344 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
345 if (!strncasecmp(find->file, partial, len) && ++count > n) {
346 res = ast_strdup(find->file);
350 AST_RWLIST_UNLOCK(&file_versions);
354 /*! \brief Find version for given module name */
355 const char *ast_file_version_find(const char *file)
357 struct file_version *iterator;
359 AST_RWLIST_WRLOCK(&file_versions);
360 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, iterator, list) {
361 if (!strcasecmp(iterator->file, file))
364 AST_RWLIST_TRAVERSE_SAFE_END;
365 AST_RWLIST_UNLOCK(&file_versions);
367 return iterator->version;
373 struct thread_list_t {
374 AST_RWLIST_ENTRY(thread_list_t) list;
379 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
381 void ast_register_thread(char *name)
383 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
387 new->id = pthread_self();
388 new->name = name; /* steal the allocated memory for the thread name */
389 AST_RWLIST_WRLOCK(&thread_list);
390 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
391 AST_RWLIST_UNLOCK(&thread_list);
394 void ast_unregister_thread(void *id)
396 struct thread_list_t *x;
398 AST_RWLIST_WRLOCK(&thread_list);
399 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
400 if ((void *) x->id == id) {
401 AST_RWLIST_REMOVE_CURRENT(list);
405 AST_RWLIST_TRAVERSE_SAFE_END;
406 AST_RWLIST_UNLOCK(&thread_list);
413 /*! \brief Give an overview of core settings */
414 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
422 e->command = "core show settings";
423 e->usage = "Usage: core show settings\n"
424 " Show core misc settings";
430 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
432 ast_cli(a->fd, "\nPBX Core settings\n");
433 ast_cli(a->fd, "-----------------\n");
434 ast_cli(a->fd, " Version: %s\n", ast_get_version());
435 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
437 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
439 ast_cli(a->fd, " Maximum calls: Not set\n");
441 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
443 ast_cli(a->fd, " Maximum open file handles: Not set\n");
444 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
445 ast_cli(a->fd, " Debug level: %d\n", option_debug);
446 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
447 #if defined(HAVE_SYSINFO)
448 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
450 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
451 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
452 ast_cli(a->fd, " Startup time: %s\n", buf);
454 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
455 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
456 ast_cli(a->fd, " Last reload time: %s\n", buf);
458 ast_cli(a->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);
459 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
460 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
461 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
462 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
463 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
464 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
465 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
466 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
467 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
469 ast_cli(a->fd, "\n* Subsystems\n");
470 ast_cli(a->fd, " -------------\n");
471 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
472 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
473 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
474 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
476 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
478 ast_cli(a->fd, "\n* Directories\n");
479 ast_cli(a->fd, " -------------\n");
480 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
481 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
482 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
483 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
484 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
485 ast_cli(a->fd, "\n\n");
489 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
492 struct thread_list_t *cur;
495 e->command = "core show threads";
497 "Usage: core show threads\n"
498 " List threads currently active in the system.\n";
504 AST_RWLIST_RDLOCK(&thread_list);
505 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
506 ast_cli(a->fd, "%p %s\n", (void *)cur->id, cur->name);
509 AST_RWLIST_UNLOCK(&thread_list);
510 ast_cli(a->fd, "%d threads listed.\n", count);
514 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
516 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
517 * to be based on the new swapctl(2) system call.
519 static int swapmode(int *used, int *total)
521 struct swapent *swdev;
522 int nswap, rnswap, i;
524 nswap = swapctl(SWAP_NSWAP, 0, 0);
528 swdev = ast_calloc(nswap, sizeof(*swdev));
532 rnswap = swapctl(SWAP_STATS, swdev, nswap);
538 /* if rnswap != nswap, then what? */
540 /* Total things up */
542 for (i = 0; i < nswap; i++) {
543 if (swdev[i].se_flags & SWF_ENABLE) {
544 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
545 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
551 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
552 static int swapmode(int *used, int *total)
559 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
560 /*! \brief Give an overview of system statistics */
561 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
563 int64_t physmem, freeram;
564 int totalswap = 0, freeswap = 0, nprocs = 0;
566 #if defined(HAVE_SYSINFO)
567 struct sysinfo sys_info;
569 uptime = sys_info.uptime/3600;
570 physmem = sys_info.totalram * sys_info.mem_unit;
571 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
572 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
573 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
574 nprocs = sys_info.procs;
575 #elif defined(HAVE_SYSCTL)
576 static int pageshift;
577 struct vmtotal vmtotal;
578 struct timeval boottime;
580 int mib[2], pagesize, usedswap = 0;
582 /* calculate the uptime by looking at boottime */
585 mib[1] = KERN_BOOTTIME;
586 len = sizeof(boottime);
587 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
588 uptime = now - boottime.tv_sec;
590 uptime = uptime/3600;
591 /* grab total physical memory */
593 #if defined(HW_PHYSMEM64)
594 mib[1] = HW_PHYSMEM64;
598 len = sizeof(physmem);
599 sysctl(mib, 2, &physmem, &len, NULL, 0);
601 pagesize = getpagesize();
603 while (pagesize > 1) {
608 /* we only need the amount of log(2)1024 for our conversion */
614 len = sizeof(vmtotal);
615 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
616 freeram = (vmtotal.t_free << pageshift);
617 /* generate swap usage and totals */
618 swapmode(&usedswap, &totalswap);
619 freeswap = (totalswap - usedswap);
620 /* grab number of processes */
621 #if defined(__OpenBSD__)
623 mib[1] = KERN_NPROCS;
624 len = sizeof(nprocs);
625 sysctl(mib, 2, &nprocs, &len, NULL, 0);
631 e->command = "core show sysinfo";
633 "Usage: core show sysinfo\n"
634 " List current system information.\n";
640 ast_cli(a->fd, "\nSystem Statistics\n");
641 ast_cli(a->fd, "-----------------\n");
642 ast_cli(a->fd, " System Uptime: %ld hours\n", uptime);
643 ast_cli(a->fd, " Total RAM: %ld KiB\n", (long)physmem/1024);
644 ast_cli(a->fd, " Free RAM: %ld KiB\n", (long)freeram);
645 #if defined(HAVE_SYSINFO)
646 ast_cli(a->fd, " Buffer RAM: %ld KiB\n", (sys_info.bufferram * sys_info.mem_unit)/1024);
648 ast_cli(a->fd, " Total Swap Space: %ld KiB\n", (long)totalswap);
649 ast_cli(a->fd, " Free Swap Space: %ld KiB\n\n", (long)freeswap);
650 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
655 struct profile_entry {
657 uint64_t scale; /* if non-zero, values are scaled by this */
663 struct profile_data {
666 struct profile_entry e[0];
669 static struct profile_data *prof_data;
671 /*! \brief allocates a counter with a given name and scale.
672 * \return Returns the identifier of the counter.
674 int ast_add_profile(const char *name, uint64_t scale)
676 int l = sizeof(struct profile_data);
677 int n = 10; /* default entries */
679 if (prof_data == NULL) {
680 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
681 if (prof_data == NULL)
683 prof_data->entries = 0;
684 prof_data->max_size = n;
686 if (prof_data->entries >= prof_data->max_size) {
688 n = prof_data->max_size + 20;
689 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
693 prof_data->max_size = n;
695 n = prof_data->entries++;
696 prof_data->e[n].name = ast_strdup(name);
697 prof_data->e[n].value = 0;
698 prof_data->e[n].events = 0;
699 prof_data->e[n].mark = 0;
700 prof_data->e[n].scale = scale;
704 int64_t ast_profile(int i, int64_t delta)
706 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
708 if (prof_data->e[i].scale > 1)
709 delta /= prof_data->e[i].scale;
710 prof_data->e[i].value += delta;
711 prof_data->e[i].events++;
712 return prof_data->e[i].value;
715 /* The RDTSC instruction was introduced on the Pentium processor and is not
716 * implemented on certain clones, like the Cyrix 586. Hence, the previous
717 * expectation of __i386__ was in error. */
718 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
719 #if defined(__FreeBSD__)
720 #include <machine/cpufunc.h>
722 static __inline uint64_t
727 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
731 #else /* supply a dummy function on other platforms */
732 static __inline uint64_t
739 int64_t ast_mark(int i, int startstop)
741 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
744 prof_data->e[i].mark = rdtsc();
746 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
747 if (prof_data->e[i].scale > 1)
748 prof_data->e[i].mark /= prof_data->e[i].scale;
749 prof_data->e[i].value += prof_data->e[i].mark;
750 prof_data->e[i].events++;
752 return prof_data->e[i].mark;
755 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
756 max = prof_data->entries;\
757 if (a->argc > 3) { /* specific entries */ \
758 if (isdigit(a->argv[3][0])) { \
759 min = atoi(a->argv[3]); \
760 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
761 max = atoi(a->argv[4]); \
763 search = a->argv[3]; \
765 if (max > prof_data->entries) \
766 max = prof_data->entries;
768 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
771 const char *search = NULL;
774 e->command = "core show profile";
775 e->usage = "Usage: core show profile\n"
776 " show profile information";
782 if (prof_data == NULL)
785 DEFINE_PROFILE_MIN_MAX_VALUES;
786 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
787 prof_data->entries, prof_data->max_size);
788 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
789 "Value", "Average", "Name");
790 for (i = min; i < max; i++) {
791 struct profile_entry *entry = &prof_data->e[i];
792 if (!search || strstr(entry->name, search))
793 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
796 (long)entry->events, (long long)entry->value,
797 (long long)(entry->events ? entry->value / entry->events : entry->value),
803 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
806 const char *search = NULL;
809 e->command = "core clear profile";
810 e->usage = "Usage: core clear profile\n"
811 " clear profile information";
817 if (prof_data == NULL)
820 DEFINE_PROFILE_MIN_MAX_VALUES;
821 for (i= min; i < max; i++) {
822 if (!search || strstr(prof_data->e[i].name, search)) {
823 prof_data->e[i].value = 0;
824 prof_data->e[i].events = 0;
829 #undef DEFINE_PROFILE_MIN_MAX_VALUES
831 /*! \brief CLI command to list module versions */
832 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
834 #define FORMAT "%-25.25s %-40.40s\n"
835 struct file_version *iterator;
841 int matchlen, which = 0;
842 struct file_version *find;
846 e->command = "core show file version [like]";
848 "Usage: core show file version [like <pattern>]\n"
849 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
850 " Optional regular expression pattern is used to filter the file list.\n";
853 matchlen = strlen(a->word);
856 AST_RWLIST_RDLOCK(&file_versions);
857 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
858 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
859 ret = ast_strdup(find->file);
863 AST_RWLIST_UNLOCK(&file_versions);
870 if (!strcasecmp(a->argv[4], "like")) {
871 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
872 return CLI_SHOWUSAGE;
875 return CLI_SHOWUSAGE;
883 return CLI_SHOWUSAGE;
886 ast_cli(a->fd, FORMAT, "File", "Revision");
887 ast_cli(a->fd, FORMAT, "----", "--------");
888 AST_RWLIST_RDLOCK(&file_versions);
889 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
890 if (havename && strcasecmp(iterator->file, a->argv[4]))
893 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
896 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
901 AST_RWLIST_UNLOCK(&file_versions);
903 ast_cli(a->fd, "%d files listed.\n", count_files);
913 #endif /* ! LOW_MEMORY */
915 int ast_register_atexit(void (*func)(void))
917 struct ast_atexit *ae;
919 if (!(ae = ast_calloc(1, sizeof(*ae))))
924 ast_unregister_atexit(func);
926 AST_RWLIST_WRLOCK(&atexits);
927 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
928 AST_RWLIST_UNLOCK(&atexits);
933 void ast_unregister_atexit(void (*func)(void))
935 struct ast_atexit *ae = NULL;
937 AST_RWLIST_WRLOCK(&atexits);
938 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
939 if (ae->func == func) {
940 AST_RWLIST_REMOVE_CURRENT(list);
944 AST_RWLIST_TRAVERSE_SAFE_END;
945 AST_RWLIST_UNLOCK(&atexits);
950 /* Sending commands from consoles back to the daemon requires a terminating NULL */
951 static int fdsend(int fd, const char *s)
953 return write(fd, s, strlen(s) + 1);
956 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
957 static int fdprint(int fd, const char *s)
959 return write(fd, s, strlen(s));
962 /*! \brief NULL handler so we can collect the child exit status */
963 static void null_sig_handler(int sig)
968 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
969 /*! \brief Keep track of how many threads are currently trying to wait*() on
971 static unsigned int safe_system_level = 0;
972 static void *safe_system_prev_handler;
974 void ast_replace_sigchld(void)
978 ast_mutex_lock(&safe_system_lock);
979 level = safe_system_level++;
981 /* only replace the handler if it has not already been done */
983 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
985 ast_mutex_unlock(&safe_system_lock);
988 void ast_unreplace_sigchld(void)
992 ast_mutex_lock(&safe_system_lock);
993 level = --safe_system_level;
995 /* only restore the handler if we are the last one */
997 signal(SIGCHLD, safe_system_prev_handler);
999 ast_mutex_unlock(&safe_system_lock);
1002 int ast_safe_system(const char *s)
1006 struct rusage rusage;
1009 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1010 ast_replace_sigchld();
1012 #ifdef HAVE_WORKING_FORK
1020 cap_t cap = cap_from_text("cap_net_admin-eip");
1022 if (cap_set_proc(cap)) {
1023 /* Careful with order! Logging cannot happen after we close FDs */
1024 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1028 #ifdef HAVE_WORKING_FORK
1029 if (ast_opt_high_priority)
1030 ast_set_priority(0);
1031 /* Close file descriptors and launch system command */
1032 ast_close_fds_above_n(STDERR_FILENO);
1034 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1036 } else if (pid > 0) {
1038 res = wait4(pid, &status, 0, &rusage);
1040 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1042 } else if (errno != EINTR)
1046 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1050 ast_unreplace_sigchld();
1051 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1058 void ast_console_toggle_loglevel(int fd, int level, int state)
1061 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1062 if (fd == consoles[x].fd) {
1063 consoles[x].levels[level] = state;
1070 * \brief mute or unmute a console from logging
1072 void ast_console_toggle_mute(int fd, int silent) {
1074 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1075 if (fd == consoles[x].fd) {
1076 if (consoles[x].mute) {
1077 consoles[x].mute = 0;
1079 ast_cli(fd, "Console is not muted anymore.\n");
1081 consoles[x].mute = 1;
1083 ast_cli(fd, "Console is muted.\n");
1088 ast_cli(fd, "Couldn't find remote console.\n");
1092 * \brief log the string to all attached console clients
1094 static void ast_network_puts_mutable(const char *string, int level)
1097 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1098 if (consoles[x].mute)
1100 if (consoles[x].fd > -1) {
1101 if (!consoles[x].levels[level])
1102 fdprint(consoles[x].p[1], string);
1108 * \brief log the string to the console, and all attached
1111 void ast_console_puts_mutable(const char *string, int level)
1113 fputs(string, stdout);
1115 ast_network_puts_mutable(string, level);
1119 * \brief write the string to all attached console clients
1121 static void ast_network_puts(const char *string)
1124 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1125 if (consoles[x].fd > -1)
1126 fdprint(consoles[x].p[1], string);
1131 * write the string to the console, and all attached
1134 void ast_console_puts(const char *string)
1136 fputs(string, stdout);
1138 ast_network_puts(string);
1141 static void network_verboser(const char *s)
1143 ast_network_puts_mutable(s, __LOG_VERBOSE);
1146 static pthread_t lthread;
1149 * \brief read() function supporting the reception of user credentials.
1151 * \param fd Socket file descriptor.
1152 * \param buffer Receive buffer.
1153 * \param size 'buffer' size.
1154 * \param con Console structure to set received credentials
1155 * \retval -1 on error
1156 * \retval the number of bytes received on success.
1158 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1160 #if defined(SO_PEERCRED)
1162 socklen_t len = sizeof(cred);
1164 #if defined(HAVE_GETPEEREID)
1172 result = read(fd, buffer, size);
1177 #if defined(SO_PEERCRED)
1178 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1183 #elif defined(HAVE_GETPEEREID)
1184 if (getpeereid(fd, &uid, &gid)) {
1196 static void *netconsole(void *vconsole)
1198 struct console *con = vconsole;
1199 char hostname[MAXHOSTNAMELEN] = "";
1202 struct pollfd fds[2];
1204 if (gethostname(hostname, sizeof(hostname)-1))
1205 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1206 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1207 fdprint(con->fd, tmp);
1209 fds[0].fd = con->fd;
1210 fds[0].events = POLLIN;
1212 fds[1].fd = con->p[0];
1213 fds[1].events = POLLIN;
1216 res = ast_poll(fds, 2, -1);
1219 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1222 if (fds[0].revents) {
1223 res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
1228 if (strncmp(tmp, "cli quit after ", 15) == 0) {
1229 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
1232 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
1234 if (fds[1].revents) {
1235 res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
1237 ast_log(LOG_ERROR, "read returned %d\n", res);
1240 res = write(con->fd, tmp, res);
1245 if (!ast_opt_hide_connect) {
1246 ast_verb(3, "Remote UNIX connection disconnected\n");
1256 static void *listener(void *unused)
1258 struct sockaddr_un sunaddr;
1263 struct pollfd fds[1];
1267 fds[0].fd = ast_socket;
1268 fds[0].events = POLLIN;
1269 s = ast_poll(fds, 1, -1);
1270 pthread_testcancel();
1273 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1276 len = sizeof(sunaddr);
1277 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1280 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1282 #if !defined(SO_PASSCRED)
1286 /* turn on socket credentials passing. */
1287 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1288 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1291 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1292 if (consoles[x].fd >= 0) {
1295 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1296 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1297 consoles[x].fd = -1;
1298 fdprint(s, "Server failed to create pipe\n");
1302 flags = fcntl(consoles[x].p[1], F_GETFL);
1303 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1305 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1306 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1307 to know if the user didn't send the credentials. */
1308 consoles[x].uid = -2;
1309 consoles[x].gid = -2;
1310 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1311 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1312 close(consoles[x].p[0]);
1313 close(consoles[x].p[1]);
1314 consoles[x].fd = -1;
1315 fdprint(s, "Server failed to spawn thread\n");
1320 if (x >= AST_MAX_CONNECTS) {
1321 fdprint(s, "No more connections allowed\n");
1322 ast_log(LOG_WARNING, "No more connections allowed\n");
1324 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1325 ast_verb(3, "Remote UNIX connection\n");
1333 static int ast_makesocket(void)
1335 struct sockaddr_un sunaddr;
1341 for (x = 0; x < AST_MAX_CONNECTS; x++)
1342 consoles[x].fd = -1;
1343 unlink(ast_config_AST_SOCKET);
1344 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1345 if (ast_socket < 0) {
1346 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1349 memset(&sunaddr, 0, sizeof(sunaddr));
1350 sunaddr.sun_family = AF_LOCAL;
1351 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1352 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1354 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1359 res = listen(ast_socket, 2);
1361 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1366 if (ast_register_verbose(network_verboser)) {
1367 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1370 ast_pthread_create_background(<hread, NULL, listener, NULL);
1372 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1374 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1375 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1380 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1382 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1383 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1388 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1389 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1391 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1394 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1396 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1397 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1403 static int ast_tryconnect(void)
1405 struct sockaddr_un sunaddr;
1407 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1408 if (ast_consock < 0) {
1409 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1412 memset(&sunaddr, 0, sizeof(sunaddr));
1413 sunaddr.sun_family = AF_LOCAL;
1414 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1415 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1424 /*! \brief Urgent handler
1426 Called by soft_hangup to interrupt the poll, read, or other
1427 system call. We don't actually need to do anything though.
1428 Remember: Cannot EVER ast_log from within a signal handler
1430 static void urg_handler(int num)
1432 signal(num, urg_handler);
1436 static void hup_handler(int num)
1439 if (option_verbose > 1)
1440 printf("Received HUP signal -- Reloading configs\n");
1442 execvp(_argv[0], _argv);
1443 sig_flags.need_reload = 1;
1444 if (sig_alert_pipe[1] != -1) {
1445 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1446 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1449 signal(num, hup_handler);
1452 static void child_handler(int sig)
1454 /* Must not ever ast_log or ast_verbose within signal handler */
1458 * Reap all dead children -- not just one
1460 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1462 if (n == 0 && option_debug)
1463 printf("Huh? Child handler, but nobody there?\n");
1464 signal(sig, child_handler);
1467 /*! \brief Set maximum open files */
1468 static void set_ulimit(int value)
1470 struct rlimit l = {0, 0};
1473 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1480 if (setrlimit(RLIMIT_NOFILE, &l)) {
1481 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1485 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1490 /*! \brief Set an X-term or screen title */
1491 static void set_title(char *text)
1493 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1494 fprintf(stdout, "\033]2;%s\007", text);
1497 static void set_icon(char *text)
1499 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1500 fprintf(stdout, "\033]1;%s\007", text);
1503 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1504 else. If your PBX has heavy activity on it, this is a good thing. */
1505 int ast_set_priority(int pri)
1507 struct sched_param sched;
1508 memset(&sched, 0, sizeof(sched));
1511 sched.sched_priority = 10;
1512 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1513 ast_log(LOG_WARNING, "Unable to set high priority\n");
1517 ast_verbose("Set to realtime thread\n");
1519 sched.sched_priority = 0;
1520 /* According to the manpage, these parameters can never fail. */
1521 sched_setscheduler(0, SCHED_OTHER, &sched);
1525 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1526 ast_log(LOG_WARNING, "Unable to set high priority\n");
1530 ast_verbose("Set to high priority\n");
1532 /* According to the manpage, these parameters can never fail. */
1533 setpriority(PRIO_PROCESS, 0, 0);
1539 static void ast_run_atexits(void)
1541 struct ast_atexit *ae;
1542 AST_RWLIST_RDLOCK(&atexits);
1543 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1547 AST_RWLIST_UNLOCK(&atexits);
1550 static void quit_handler(int num, int niceness, int safeshutdown, int restart)
1552 char filename[80] = "";
1555 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1556 ast_cdr_engine_term();
1560 /* Begin shutdown routine, hanging up active channels */
1561 ast_begin_shutdown(1);
1562 if (option_verbose && ast_opt_console)
1563 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1567 /* Wait up to 15 seconds for all channels to go away */
1570 if (!ast_active_channels())
1574 /* Sleep 1/10 of a second */
1579 ast_begin_shutdown(0);
1580 if (option_verbose && ast_opt_console)
1581 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1583 if (!ast_active_channels())
1591 if (!shuttingdown) {
1592 if (option_verbose && ast_opt_console)
1593 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1598 ast_module_shutdown();
1600 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1602 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1603 if (!ast_strlen_zero(filename))
1604 ast_el_write_history(filename);
1607 if (el_hist != NULL)
1608 history_end(el_hist);
1611 ast_verbose("Executing last minute cleanups\n");
1613 /* Called on exit */
1614 if (option_verbose && ast_opt_console)
1615 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1616 ast_debug(1, "Asterisk ending (%d).\n", num);
1617 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1618 if (ast_socket > -1) {
1619 pthread_cancel(lthread);
1622 unlink(ast_config_AST_SOCKET);
1624 if (ast_consock > -1)
1626 if (!ast_opt_remote)
1627 unlink(ast_config_AST_PID);
1628 printf("%s", term_quit());
1630 if (option_verbose || ast_opt_console)
1631 ast_verbose("Preparing for Asterisk restart...\n");
1632 /* Mark all FD's for closing on exec */
1633 for (x=3; x < 32768; x++) {
1634 fcntl(x, F_SETFD, FD_CLOEXEC);
1636 if (option_verbose || ast_opt_console)
1637 ast_verbose("Asterisk is now restarting...\n");
1643 /* If there is a consolethread running send it a SIGHUP
1644 so it can execvp, otherwise we can do it ourselves */
1645 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1646 pthread_kill(consolethread, SIGHUP);
1647 /* Give the signal handler some time to complete */
1650 execvp(_argv[0], _argv);
1659 static void __quit_handler(int num)
1662 sig_flags.need_quit = 1;
1663 if (sig_alert_pipe[1] != -1) {
1664 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1665 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1668 /* There is no need to restore the signal handler here, since the app
1669 * is going to exit */
1672 static void __remote_quit_handler(int num)
1674 sig_flags.need_quit = 1;
1677 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1681 /* Check for verboser preamble */
1686 if (!strncmp(s, cmp, strlen(cmp))) {
1687 c = s + strlen(cmp);
1688 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1694 static void console_verboser(const char *s)
1697 const char *c = NULL;
1699 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1700 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1701 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1702 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1714 /* Wake up a poll()ing console */
1715 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1716 pthread_kill(consolethread, SIGURG);
1719 static int ast_all_zeros(char *s)
1729 static void consolehandler(char *s)
1731 printf("%s", term_end());
1734 /* Called when readline data is available */
1735 if (!ast_all_zeros(s))
1736 ast_el_add_history(s);
1737 /* The real handler for bang */
1740 ast_safe_system(s+1);
1742 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1744 ast_cli_command(STDOUT_FILENO, s);
1747 static int remoteconsolehandler(char *s)
1751 /* Called when readline data is available */
1752 if (!ast_all_zeros(s))
1753 ast_el_add_history(s);
1754 /* The real handler for bang */
1757 ast_safe_system(s+1);
1759 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1762 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1763 (s[4] == '\0' || isspace(s[4]))) {
1764 quit_handler(0, 0, 0, 0);
1771 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1775 e->command = "core show version";
1777 "Usage: core show version\n"
1778 " Shows Asterisk version information.\n";
1785 return CLI_SHOWUSAGE;
1786 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1787 ast_get_version(), ast_build_user, ast_build_hostname,
1788 ast_build_machine, ast_build_os, ast_build_date);
1793 static int handle_quit(int fd, int argc, char *argv[])
1796 return RESULT_SHOWUSAGE;
1797 quit_handler(0, 0, 1, 0);
1798 return RESULT_SUCCESS;
1802 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1806 e->command = "core stop now";
1808 "Usage: core stop now\n"
1809 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1815 if (a->argc != e->args)
1816 return CLI_SHOWUSAGE;
1817 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1821 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1825 e->command = "core stop gracefully";
1827 "Usage: core stop gracefully\n"
1828 " Causes Asterisk to not accept new calls, and exit when all\n"
1829 " active calls have terminated normally.\n";
1835 if (a->argc != e->args)
1836 return CLI_SHOWUSAGE;
1837 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1841 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1845 e->command = "core stop when convenient";
1847 "Usage: core stop when convenient\n"
1848 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1854 if (a->argc != e->args)
1855 return CLI_SHOWUSAGE;
1856 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
1857 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1861 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1865 e->command = "core restart now";
1867 "Usage: core restart now\n"
1868 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1875 if (a->argc != e->args)
1876 return CLI_SHOWUSAGE;
1877 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1881 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1885 e->command = "core restart gracefully";
1887 "Usage: core restart gracefully\n"
1888 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1889 " restart when all active calls have ended.\n";
1895 if (a->argc != e->args)
1896 return CLI_SHOWUSAGE;
1897 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1901 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1905 e->command = "core restart when convenient";
1907 "Usage: core restart when convenient\n"
1908 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1914 if (a->argc != e->args)
1915 return CLI_SHOWUSAGE;
1916 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
1917 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1921 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1925 e->command = "core abort shutdown";
1927 "Usage: core abort shutdown\n"
1928 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1929 " call operations.\n";
1935 if (a->argc != e->args)
1936 return CLI_SHOWUSAGE;
1937 ast_cancel_shutdown();
1942 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1948 "Usage: !<command>\n"
1949 " Executes a given shell command\n";
1957 static const char warranty_lines[] = {
1961 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
1962 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
1963 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
1964 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
1965 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
1966 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
1967 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
1968 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
1969 "REPAIR OR CORRECTION.\n"
1971 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
1972 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
1973 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
1974 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
1975 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
1976 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
1977 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
1978 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
1979 "POSSIBILITY OF SUCH DAMAGES.\n"
1982 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1986 e->command = "core show warranty";
1988 "Usage: core show warranty\n"
1989 " Shows the warranty (if any) for this copy of Asterisk.\n";
1995 ast_cli(a->fd, "%s", warranty_lines);
2000 static const char license_lines[] = {
2002 "This program is free software; you can redistribute it and/or modify\n"
2003 "it under the terms of the GNU General Public License version 2 as\n"
2004 "published by the Free Software Foundation.\n"
2006 "This program also contains components licensed under other licenses.\n"
2009 "This program is distributed in the hope that it will be useful,\n"
2010 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2011 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2012 "GNU General Public License for more details.\n"
2014 "You should have received a copy of the GNU General Public License\n"
2015 "along with this program; if not, write to the Free Software\n"
2016 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2019 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2023 e->command = "core show license";
2025 "Usage: core show license\n"
2026 " Shows the license(s) for this copy of Asterisk.\n";
2032 ast_cli(a->fd, "%s", license_lines);
2037 #define ASTERISK_PROMPT "*CLI> "
2039 #define ASTERISK_PROMPT2 "%s*CLI> "
2041 static struct ast_cli_entry cli_asterisk[] = {
2042 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2043 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2044 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2045 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2046 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2047 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2048 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2049 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2050 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2051 AST_CLI_DEFINE(handle_version, "Display version info"),
2052 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2053 #if !defined(LOW_MEMORY)
2054 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2055 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2056 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2057 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2059 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2060 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2061 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2062 #endif /* ! LOW_MEMORY */
2065 static int ast_el_read_char(EditLine *editline, char *cp)
2069 struct pollfd fds[2];
2072 #define EL_BUF_SIZE 512
2073 char buf[EL_BUF_SIZE];
2077 fds[0].fd = ast_consock;
2078 fds[0].events = POLLIN;
2079 if (!ast_opt_exec) {
2080 fds[1].fd = STDIN_FILENO;
2081 fds[1].events = POLLIN;
2084 res = ast_poll(fds, max, -1);
2086 if (sig_flags.need_quit)
2090 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2094 if (!ast_opt_exec && fds[1].revents) {
2095 num_read = read(STDIN_FILENO, cp, 1);
2101 if (fds[0].revents) {
2103 res = read(ast_consock, buf, sizeof(buf) - 1);
2104 /* if the remote side disappears exit */
2106 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2107 if (!ast_opt_reconnect) {
2108 quit_handler(0, 0, 0, 0);
2111 int reconnects_per_second = 20;
2112 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2113 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2114 if (ast_tryconnect()) {
2115 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2116 printf("%s", term_quit());
2119 fdsend(ast_consock, "logger mute silent");
2121 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2124 usleep(1000000 / reconnects_per_second);
2126 if (tries >= 30 * reconnects_per_second) {
2127 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2128 quit_handler(0, 0, 0, 0);
2135 /* Strip preamble from asynchronous events, too */
2136 for (tmp = buf; *tmp; tmp++) {
2138 memmove(tmp, tmp + 1, strlen(tmp));
2144 /* Write over the CLI prompt */
2145 if (!ast_opt_exec && !lastpos) {
2146 if (write(STDOUT_FILENO, "\r", 1) < 0) {
2149 if (write(STDOUT_FILENO, buf, res) < 0) {
2151 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2163 static struct ast_str *prompt = NULL;
2165 static char *cli_prompt(EditLine *editline)
2170 static int cli_prompt_changes = 0;
2175 if (prompt == NULL) {
2176 prompt = ast_str_create(100);
2177 } else if (!cli_prompt_changes) {
2178 return ast_str_buffer(prompt);
2180 ast_str_reset(prompt);
2183 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2185 struct timeval ts = ast_tvnow();
2186 while (*t != '\0') {
2188 char hostname[MAXHOSTNAMELEN] = "";
2190 struct ast_tm tm = { 0, };
2191 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2195 case 'C': /* color */
2197 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2198 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2200 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2201 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2205 /* If the color has been reset correctly, then there's no need to reset it later */
2206 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2208 case 'd': /* date */
2209 if (ast_localtime(&ts, &tm, NULL)) {
2210 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2211 ast_str_append(&prompt, 0, "%s", tmp);
2212 cli_prompt_changes++;
2215 case 'g': /* group */
2216 if ((gr = getgrgid(getgid()))) {
2217 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2220 case 'h': /* hostname */
2221 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2222 ast_str_append(&prompt, 0, "%s", hostname);
2224 ast_str_append(&prompt, 0, "%s", "localhost");
2227 case 'H': /* short hostname */
2228 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2230 if ((dotptr = strchr(hostname, '.'))) {
2233 ast_str_append(&prompt, 0, "%s", hostname);
2235 ast_str_append(&prompt, 0, "%s", "localhost");
2238 #ifdef HAVE_GETLOADAVG
2239 case 'l': /* load avg */
2241 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2243 getloadavg(list, 3);
2244 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2245 cli_prompt_changes++;
2249 case 's': /* Asterisk system name (from asterisk.conf) */
2250 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2252 case 't': /* time */
2253 if (ast_localtime(&ts, &tm, NULL)) {
2254 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2255 ast_str_append(&prompt, 0, "%s", tmp);
2256 cli_prompt_changes++;
2259 case 'u': /* username */
2260 if ((pw = getpwuid(getuid()))) {
2261 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2264 case '#': /* process console or remote? */
2265 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2267 case '%': /* literal % */
2268 ast_str_append(&prompt, 0, "%c", '%');
2270 case '\0': /* % is last character - prevent bug */
2275 ast_str_append(&prompt, 0, "%c", *t);
2280 /* Force colors back to normal at end */
2281 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2283 } else if (remotehostname) {
2284 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2286 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2289 return ast_str_buffer(prompt);
2292 static char **ast_el_strtoarr(char *buf)
2294 char **match_list = NULL, **match_list_tmp, *retstr;
2295 size_t match_list_len;
2299 while ( (retstr = strsep(&buf, " ")) != NULL) {
2301 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2303 if (matches + 1 >= match_list_len) {
2304 match_list_len <<= 1;
2305 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2306 match_list = match_list_tmp;
2309 ast_free(match_list);
2310 return (char **) NULL;
2314 match_list[matches++] = ast_strdup(retstr);
2318 return (char **) NULL;
2320 if (matches >= match_list_len) {
2321 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2322 match_list = match_list_tmp;
2325 ast_free(match_list);
2326 return (char **) NULL;
2330 match_list[matches] = (char *) NULL;
2335 static int ast_el_sort_compare(const void *i1, const void *i2)
2339 s1 = ((char **)i1)[0];
2340 s2 = ((char **)i2)[0];
2342 return strcasecmp(s1, s2);
2345 static int ast_cli_display_match_list(char **matches, int len, int max)
2347 int i, idx, limit, count;
2348 int screenwidth = 0;
2349 int numoutput = 0, numoutputline = 0;
2351 screenwidth = ast_get_termcols(STDOUT_FILENO);
2353 /* find out how many entries can be put on one line, with two spaces between strings */
2354 limit = screenwidth / (max + 2);
2358 /* how many lines of output */
2359 count = len / limit;
2360 if (count * limit < len)
2365 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2367 for (; count > 0; count--) {
2369 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2371 /* Don't print dupes */
2372 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2374 ast_free(matches[idx]);
2375 matches[idx] = NULL;
2381 fprintf(stdout, "%-*s ", max, matches[idx]);
2382 ast_free(matches[idx]);
2383 matches[idx] = NULL;
2385 if (numoutputline > 0)
2386 fprintf(stdout, "\n");
2393 static char *cli_complete(EditLine *editline, int ch)
2399 int retval = CC_ERROR;
2400 char buf[2048], savechr;
2403 LineInfo *lf = (LineInfo *)el_line(editline);
2405 savechr = *(char *)lf->cursor;
2406 *(char *)lf->cursor = '\0';
2407 ptr = (char *)lf->cursor;
2409 while (ptr > lf->buffer) {
2410 if (isspace(*ptr)) {
2418 len = lf->cursor - ptr;
2420 if (ast_opt_remote) {
2421 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2422 fdsend(ast_consock, buf);
2423 res = read(ast_consock, buf, sizeof(buf) - 1);
2425 nummatches = atoi(buf);
2427 if (nummatches > 0) {
2429 int mlen = 0, maxmbuf = 2048;
2430 /* Start with a 2048 byte buffer */
2431 if (!(mbuf = ast_malloc(maxmbuf))) {
2432 lf->cursor[0] = savechr;
2433 return (char *)(CC_ERROR);
2435 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2436 fdsend(ast_consock, buf);
2439 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2440 if (mlen + 1024 > maxmbuf) {
2441 /* Every step increment buffer 1024 bytes */
2443 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2444 lf->cursor[0] = savechr;
2445 return (char *)(CC_ERROR);
2448 /* Only read 1024 bytes at a time */
2449 res = read(ast_consock, mbuf + mlen, 1024);
2455 matches = ast_el_strtoarr(mbuf);
2458 matches = (char **) NULL;
2460 char **p, *oldbuf=NULL;
2462 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2463 for (p = matches; p && *p; p++) {
2464 if (!oldbuf || strcmp(*p,oldbuf))
2472 int matches_num, maxlen, match_len;
2474 if (matches[0][0] != '\0') {
2475 el_deletestr(editline, (int) len);
2476 el_insertstr(editline, matches[0]);
2477 retval = CC_REFRESH;
2480 if (nummatches == 1) {
2481 /* Found an exact match */
2482 el_insertstr(editline, " ");
2483 retval = CC_REFRESH;
2485 /* Must be more than one match */
2486 for (i = 1, maxlen = 0; matches[i]; i++) {
2487 match_len = strlen(matches[i]);
2488 if (match_len > maxlen)
2491 matches_num = i - 1;
2492 if (matches_num >1) {
2493 fprintf(stdout, "\n");
2494 ast_cli_display_match_list(matches, nummatches, maxlen);
2495 retval = CC_REDISPLAY;
2497 el_insertstr(editline," ");
2498 retval = CC_REFRESH;
2501 for (i = 0; matches[i]; i++)
2502 ast_free(matches[i]);
2506 lf->cursor[0] = savechr;
2508 return (char *)(long)retval;
2511 static int ast_el_initialize(void)
2514 char *editor = getenv("AST_EDITOR");
2518 if (el_hist != NULL)
2519 history_end(el_hist);
2521 el = el_init("asterisk", stdin, stdout, stderr);
2522 el_set(el, EL_PROMPT, cli_prompt);
2524 el_set(el, EL_EDITMODE, 1);
2525 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2526 el_hist = history_init();
2527 if (!el || !el_hist)
2530 /* setup history with 100 entries */
2531 history(el_hist, &ev, H_SETSIZE, 100);
2533 el_set(el, EL_HIST, history, el_hist);
2535 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2536 /* Bind <tab> to command completion */
2537 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2538 /* Bind ? to command completion */
2539 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2540 /* Bind ^D to redisplay */
2541 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2546 #define MAX_HISTORY_COMMAND_LENGTH 256
2548 static int ast_el_add_history(char *buf)
2552 if (el_hist == NULL || el == NULL)
2553 ast_el_initialize();
2554 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2556 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2559 static int ast_el_write_history(char *filename)
2563 if (el_hist == NULL || el == NULL)
2564 ast_el_initialize();
2566 return (history(el_hist, &ev, H_SAVE, filename));
2569 static int ast_el_read_history(char *filename)
2571 char buf[MAX_HISTORY_COMMAND_LENGTH];
2575 if (el_hist == NULL || el == NULL)
2576 ast_el_initialize();
2578 if ((f = fopen(filename, "r")) == NULL)
2582 if (!fgets(buf, sizeof(buf), f))
2584 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2586 if (ast_all_zeros(buf))
2588 if ((ret = ast_el_add_history(buf)) == -1)
2596 static void ast_remotecontrol(char *data)
2600 char filename[80] = "";
2605 char *stringp = NULL;
2610 memset(&sig_flags, 0, sizeof(sig_flags));
2611 signal(SIGINT, __remote_quit_handler);
2612 signal(SIGTERM, __remote_quit_handler);
2613 signal(SIGHUP, __remote_quit_handler);
2615 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2616 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2620 char prefix[] = "cli quit after ";
2621 char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
2622 sprintf(tmp, "%s%s", prefix, data);
2623 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2624 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2625 if (sig_flags.need_quit == 1) {
2631 hostname = strsep(&stringp, "/");
2632 cpid = strsep(&stringp, "/");
2633 version = strsep(&stringp, "\n");
2635 version = "<Version Unknown>";
2637 strsep(&stringp, ".");
2644 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2645 fdsend(ast_consock, tmp);
2646 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2647 fdsend(ast_consock, tmp);
2649 fdsend(ast_consock, "logger mute silent");
2651 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2654 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2656 fds.fd = ast_consock;
2657 fds.events = POLLIN;
2659 while (ast_poll(&fds, 1, 500) > 0) {
2660 char buffer[512] = "", *curline = buffer, *nextline;
2661 int not_written = 1;
2663 if (sig_flags.need_quit == 1) {
2667 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
2672 if ((nextline = strchr(curline, '\n'))) {
2675 nextline = strchr(curline, '\0');
2678 /* Skip verbose lines */
2679 if (*curline != 127) {
2681 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2682 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
2686 } while (!ast_strlen_zero(curline));
2688 /* No non-verbose output in 500ms */
2696 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2697 remotehostname = hostname;
2699 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2700 if (el_hist == NULL || el == NULL)
2701 ast_el_initialize();
2703 el_set(el, EL_GETCFN, ast_el_read_char);
2705 if (!ast_strlen_zero(filename))
2706 ast_el_read_history(filename);
2709 ebuf = (char *)el_gets(el, &num);
2711 if (sig_flags.need_quit == 1) {
2715 if (!ebuf && write(1, "", 1) < 0)
2718 if (!ast_strlen_zero(ebuf)) {
2719 if (ebuf[strlen(ebuf)-1] == '\n')
2720 ebuf[strlen(ebuf)-1] = '\0';
2721 if (!remoteconsolehandler(ebuf)) {
2722 /* Strip preamble from output */
2724 for (temp = ebuf; *temp; temp++) {
2726 memmove(temp, temp + 1, strlen(temp));
2730 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2732 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2738 printf("\nDisconnected from Asterisk server\n");
2741 static int show_version(void)
2743 printf("Asterisk %s\n", ast_get_version());
2747 static int show_cli_help(void) {
2748 printf("Asterisk %s, Copyright (C) 1999 - 2009, Digium, Inc. and others.\n", ast_get_version());
2749 printf("Usage: asterisk [OPTIONS]\n");
2750 printf("Valid Options:\n");
2751 printf(" -V Display version number and exit\n");
2752 printf(" -C <configfile> Use an alternate configuration file\n");
2753 printf(" -G <group> Run as a group other than the caller\n");
2754 printf(" -U <user> Run as a user other than the caller\n");
2755 printf(" -c Provide console CLI\n");
2756 printf(" -d Enable extra debugging\n");
2757 #if HAVE_WORKING_FORK
2758 printf(" -f Do not fork\n");
2759 printf(" -F Always fork\n");
2761 printf(" -g Dump core in case of a crash\n");
2762 printf(" -h This help screen\n");
2763 printf(" -i Initialize crypto keys at startup\n");
2764 printf(" -I Enable internal timing if DAHDI timer is available\n");
2765 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2766 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2767 printf(" -m Mute debugging and console output on the console\n");
2768 printf(" -n Disable console colorization\n");
2769 printf(" -p Run as pseudo-realtime thread\n");
2770 printf(" -q Quiet mode (suppress output)\n");
2771 printf(" -r Connect to Asterisk on this machine\n");
2772 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2773 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
2774 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2775 printf(" belong after they are done\n");
2776 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2777 printf(" of output to the CLI\n");
2778 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2779 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2780 printf(" -W Adjust terminal colors to compensate for a light background\n");
2785 static void ast_readconfig(void)
2787 struct ast_config *cfg;
2788 struct ast_variable *v;
2789 char *config = DEFAULT_CONFIG_FILE;
2790 char hostname[MAXHOSTNAMELEN] = "";
2791 struct ast_flags config_flags = { 0 };
2793 unsigned int dbdir:1;
2794 unsigned int keydir:1;
2797 if (ast_opt_override_config) {
2798 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
2799 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
2800 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2802 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
2804 /* init with buildtime config */
2805 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2806 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2807 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2808 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
2809 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2810 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2811 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2812 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2813 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2814 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2815 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2816 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2817 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2819 ast_set_default_eid(&ast_eid_default);
2821 /* no asterisk.conf? no problem, use buildtime config! */
2822 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
2826 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2827 if (!strcasecmp(v->name, "astctlpermissions"))
2828 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2829 else if (!strcasecmp(v->name, "astctlowner"))
2830 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2831 else if (!strcasecmp(v->name, "astctlgroup"))
2832 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2833 else if (!strcasecmp(v->name, "astctl"))
2834 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2837 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2838 if (!strcasecmp(v->name, "astetcdir")) {
2839 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2840 } else if (!strcasecmp(v->name, "astspooldir")) {
2841 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2842 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
2843 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2844 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2846 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2847 } else if (!strcasecmp(v->name, "astdbdir")) {
2848 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2850 } else if (!strcasecmp(v->name, "astdatadir")) {
2851 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2853 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2854 } else if (!strcasecmp(v->name, "astkeydir")) {
2855 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2857 } else if (!strcasecmp(v->name, "astlogdir")) {
2858 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2859 } else if (!strcasecmp(v->name, "astagidir")) {
2860 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2861 } else if (!strcasecmp(v->name, "astrundir")) {
2862 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2863 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2864 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2865 } else if (!strcasecmp(v->name, "astmoddir")) {
2866 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2870 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2871 /* verbose level (-v at startup) */
2872 if (!strcasecmp(v->name, "verbose")) {
2873 option_verbose = atoi(v->value);
2874 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2875 } else if (!strcasecmp(v->name, "timestamp")) {
2876 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2877 /* whether or not to support #exec in config files */
2878 } else if (!strcasecmp(v->name, "execincludes")) {
2879 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2880 /* debug level (-d at startup) */
2881 } else if (!strcasecmp(v->name, "debug")) {
2883 if (sscanf(v->value, "%30d", &option_debug) != 1) {
2884 option_debug = ast_true(v->value);
2886 #if HAVE_WORKING_FORK
2887 /* Disable forking (-f at startup) */
2888 } else if (!strcasecmp(v->name, "nofork")) {
2889 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2890 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2891 } else if (!strcasecmp(v->name, "alwaysfork")) {
2892 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2894 /* Run quietly (-q at startup ) */
2895 } else if (!strcasecmp(v->name, "quiet")) {
2896 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2897 /* Run as console (-c at startup, implies nofork) */
2898 } else if (!strcasecmp(v->name, "console")) {
2899 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2900 /* Run with high priority if the O/S permits (-p at startup) */
2901 } else if (!strcasecmp(v->name, "highpriority")) {
2902 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2903 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2904 } else if (!strcasecmp(v->name, "initcrypto")) {
2905 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2906 /* Disable ANSI colors for console (-c at startup) */
2907 } else if (!strcasecmp(v->name, "nocolor")) {
2908 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2909 /* Disable some usage warnings for picky people :p */
2910 } else if (!strcasecmp(v->name, "dontwarn")) {
2911 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2912 /* Dump core in case of crash (-g) */
2913 } else if (!strcasecmp(v->name, "dumpcore")) {
2914 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2915 /* Cache recorded sound files to another directory during recording */
2916 } else if (!strcasecmp(v->name, "cache_record_files")) {
2917 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2918 /* Specify cache directory */
2919 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2920 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2921 /* Build transcode paths via SLINEAR, instead of directly */
2922 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2923 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2924 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2925 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2926 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2927 /* Enable internal timing */
2928 } else if (!strcasecmp(v->name, "internal_timing")) {
2929 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2930 } else if (!strcasecmp(v->name, "maxcalls")) {
2931 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2932 option_maxcalls = 0;
2934 } else if (!strcasecmp(v->name, "maxload")) {
2937 if (getloadavg(test, 1) == -1) {
2938 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2939 option_maxload = 0.0;
2940 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2941 option_maxload = 0.0;
2943 /* Set the maximum amount of open files */
2944 } else if (!strcasecmp(v->name, "maxfiles")) {
2945 option_maxfiles = atoi(v->value);
2946 set_ulimit(option_maxfiles);
2947 /* What user to run as */
2948 } else if (!strcasecmp(v->name, "runuser")) {
2949 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
2950 /* What group to run as */
2951 } else if (!strcasecmp(v->name, "rungroup")) {
2952 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
2953 } else if (!strcasecmp(v->name, "systemname")) {
2954 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
2955 } else if (!strcasecmp(v->name, "autosystemname")) {
2956 if (ast_true(v->value)) {
2957 if (!gethostname(hostname, sizeof(hostname) - 1))
2958 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
2960 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2961 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
2963 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2966 } else if (!strcasecmp(v->name, "languageprefix")) {
2967 ast_language_is_prefix = ast_true(v->value);
2968 } else if (!strcasecmp(v->name, "lockmode")) {
2969 if (!strcasecmp(v->value, "lockfile")) {
2970 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2971 } else if (!strcasecmp(v->value, "flock")) {
2972 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
2974 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
2975 "defaulting to 'lockfile'\n", v->value);
2976 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2978 #if defined(HAVE_SYSINFO)
2979 } else if (!strcasecmp(v->name, "minmemfree")) {
2980 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
2981 * if the amount of free memory falls below this watermark */
2982 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2983 option_minmemfree = 0;
2986 } else if (!strcasecmp(v->name, "entityid")) {
2987 struct ast_eid tmp_eid;
2988 if (!ast_str_to_eid(&tmp_eid, v->value)) {
2989 ast_verbose("Successfully set global EID to '%s'\n", v->value);
2990 ast_eid_default = tmp_eid;
2992 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
2993 } else if (!strcasecmp(v->name, "lightbackground")) {
2994 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
2995 } else if (!strcasecmp(v->name, "forceblackbackground")) {
2996 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
2997 } else if (!strcasecmp(v->name, "hideconnect")) {
2998 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3001 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3003 if (sscanf(v->value, "%30f", &version) != 1) {
3004 ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3007 if (!strcasecmp(v->name, "app_set")) {
3008 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3009 } else if (!strcasecmp(v->name, "res_agi")) {
3010 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3011 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3012 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3015 ast_config_destroy(cfg);
3018 static void *monitor_sig_flags(void *unused)
3021 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3023 ast_poll(&p, 1, -1);
3024 if (sig_flags.need_reload) {
3025 sig_flags.need_reload = 0;
3026 ast_module_reload(NULL);
3028 if (sig_flags.need_quit) {
3029 sig_flags.need_quit = 0;
3030 quit_handler(0, 0, 1, 0);
3032 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3039 static void *canary_thread(void *unused)
3041 struct stat canary_stat;
3044 /* Give the canary time to sing */
3048 stat(canary_filename, &canary_stat);
3050 if (now.tv_sec > canary_stat.st_mtime + 60) {
3051 ast_log(LOG_WARNING, "The canary is no more. He has ceased to be! He's expired and gone to meet his maker! He's a stiff! Bereft of life, he rests in peace. His metabolic processes are now history! He's off the twig! He's kicked the bucket. He's shuffled off his mortal coil, run down the curtain, and joined the bleeding choir invisible!! THIS is an EX-CANARY. (Reducing priority)\n");
3052 ast_set_priority(0);
3056 /* Check the canary once a minute */
3061 /* Used by libc's atexit(3) function */
3062 static void canary_exit(void)
3065 kill(canary_pid, SIGKILL);
3068 static void run_startup_commands(void)
3071 struct ast_config *cfg;
3072 struct ast_flags cfg_flags = { 0 };
3073 struct ast_variable *v;
3075 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3077 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3081 fd = open("/dev/null", O_RDWR);
3083 ast_config_destroy(cfg);
3087 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3088 if (ast_true(v->value))
3089 ast_cli_command(fd, v->name);
3093 ast_config_destroy(cfg);
3096 int main(int argc, char *argv[])
3099 char filename[80] = "";
3100 char hostname[MAXHOSTNAMELEN] = "";
3109 const char *runuser = NULL, *rungroup = NULL;
3110 char *remotesock = NULL;
3112 /* Remember original args for restart */
3113 if (argc > ARRAY_LEN(_argv) - 1) {
3114 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
3115 argc = ARRAY_LEN(_argv) - 1;
3117 for (x = 0; x < argc; x++)
3124 /* if the progname is rasterisk consider it a remote console */
3125 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
3126 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3128 if (gethostname(hostname, sizeof(hostname)-1))
3129 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
3130 ast_mainpid = getpid();
3134 ast_builtins_init();
3141 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3142 /* Check for options */
3143 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:s:WB")) != -1) {
3145 #if defined(HAVE_SYSINFO)
3147 if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3148 option_minmemfree = 0;
3152 #if HAVE_WORKING_FORK
3154 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
3157 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3162 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3165 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3168 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
3171 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3174 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
3177 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
3181 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3184 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
3187 if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0))
3188 option_maxcalls = 0;
3191 if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0))
3192 option_maxload = 0.0;
3195 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
3198 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
3201 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
3204 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
3205 xarg = ast_strdupa(optarg);
3208 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
3209 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
3212 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
3215 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
3218 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
3227 runuser = ast_strdupa(optarg);
3230 rungroup = ast_strdupa(optarg);
3233 remotesock = ast_strdupa(optarg);
3235 case 'W': /* White background */
3236 ast_set_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
3237 ast_clear_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3239 case 'B': /* Force black background */
3240 ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3241 ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
3248 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
3249 if (ast_register_verbose(console_verboser)) {
3250 ast_log(LOG_WARNING, "Unable to register console verboser?\n");
3255 if (ast_opt_console && !option_verbose)
3256 ast_verbose("[ Booting...\n");
3258 /* For remote connections, change the name of the remote connection.
3259 * We do this for the benefit of init scripts (which need to know if/when
3260 * the main asterisk process has died yet). */
3261 if (ast_opt_remote) {
3262 strcpy(argv[0], "rasterisk");
3263 for (x = 1; x < argc; x++) {
3264 argv[x] = argv[0] + 10;
3268 if (ast_opt_console && !option_verbose) {
3269 ast_verbose("[ Reading Master Configuration ]\n");
3274 if (ast_opt_remote && remotesock != NULL)
3275 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
3277 if (!ast_language_is_prefix && !ast_opt_remote)
3278 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");
3280 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
3281 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
3282 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
3285 if (ast_opt_dump_core) {
3287 memset(&l, 0, sizeof(l));
3288 l.rlim_cur = RLIM_INFINITY;
3289 l.rlim_max = RLIM_INFINITY;
3290 if (setrlimit(RLIMIT_CORE, &l)) {
3291 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
3295 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
3296 rungroup = ast_config_AST_RUN_GROUP;
3297 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
3298 runuser = ast_config_AST_RUN_USER;
3300 /* Must install this signal handler up here to ensure that if the canary
3301 * fails to execute that it doesn't kill the Asterisk process.
3303 signal(SIGCHLD, child_handler);
3308 ast_set_priority(ast_opt_high_priority);
3311 if (isroot && rungroup) {
3313 gr = getgrnam(rungroup);
3315 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
3318 if (setgid(gr->gr_gid)) {
3319 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
3322 if (setgroups(0, NULL)) {
3323 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
3327 ast_verbose("Running as group '%s'\n", rungroup);
3330 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
3333 #endif /* HAVE_CAP */
3335 pw = getpwnam(runuser);
3337 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
3341 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
3342 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
3345 #endif /* HAVE_CAP */
3346 if (!isroot && pw->pw_uid != geteuid()) {
3347 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
3351 if (setgid(pw->pw_gid)) {
3352 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
3355 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
3356 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
3360 if (setuid(pw->pw_uid)) {
3361 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
3365 ast_verbose("Running as user '%s'\n", runuser);
3370 cap = cap_from_text("cap_net_admin=eip");
3372 if (cap_set_proc(cap))
3373 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
3376 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
3378 #endif /* HAVE_CAP */
3381 #endif /* __CYGWIN__ */
3384 if (geteuid() && ast_opt_dump_core) {
3385 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
3386 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
3392 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
3393 #if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
3394 #define eaccess euidaccess
3397 if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
3398 ast_log(LOG_ERROR, "Unable to access the running directory (%s). Changing to '/' for compatibility.\n", strerror(errno));
3399 /* If we cannot access the CWD, then we couldn't dump core anyway,
3400 * so chdir("/") won't break anything. */
3402 /* chdir(/) should never fail, so this ends up being a no-op */
3403 ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
3406 #endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
3407 if (!ast_opt_no_fork && !ast_opt_dump_core) {
3408 /* Backgrounding, but no cores, so chdir won't break anything. */
3410 ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
3416 printf("%s", term_end());
3419 if (ast_opt_console && !option_verbose)
3420 ast_verbose("[ Initializing Custom Configuration Options ]\n");
3421 /* custom config setup */
3422 register_config_cli();
3425 if (ast_opt_console) {
3426 if (el_hist == NULL || el == NULL)
3427 ast_el_initialize();
3429 if (!ast_strlen_zero(filename))
3430 ast_el_read_history(filename);
3433 if (ast_tryconnect()) {
3434 /* One is already running */
3435 if (ast_opt_remote) {
3437 ast_remotecontrol(xarg);
3438 quit_handler(0, 0, 0, 0);
3441 printf("%s", term_quit());
3442 ast_remotecontrol(NULL);
3443 quit_handler(0, 0, 0, 0);
3446 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
3447 printf("%s", term_quit());
3450 } else if (ast_opt_remote || ast_opt_exec) {
3451 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
3452 printf("%s", term_quit());
3455 /* Blindly write pid file since we couldn't connect */
3456 unlink(ast_config_AST_PID);
3457 f = fopen(ast_config_AST_PID, "w");
3459 fprintf(f, "%ld\n", (long)getpid());
3462 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
3464 #if HAVE_WORKING_FORK
3465 if (ast_opt_always_fork || !ast_opt_no_fork) {
3466 #ifndef HAVE_SBIN_LAUNCHD
3467 if (daemon(1, 0) < 0) {
3468 ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
3470 ast_mainpid = getpid();
3471 /* Blindly re-write pid file since we are forking */
3472 unlink(ast_config_AST_PID);
3473 f = fopen(ast_config_AST_PID, "w");
3475 fprintf(f, "%ld\n", (long)ast_mainpid);
3478 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
3480 ast_log(LOG_WARNING, "Mac OS X detected. Use '/sbin/launchd -d' to launch with the nofork option.\n");
3485 /* Spawning of astcanary must happen AFTER the call to daemon(3) */
3486 if (isroot && ast_opt_high_priority) {
3489 /* PIPE signal ensures that astcanary dies when Asterisk dies */
3491 fprintf(stderr, "Unable to open pipe for canary process: %s\n", strerror(errno));
3494 canary_pipe = cpipe[0];
3496 snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
3498 /* Don't let the canary child kill Asterisk, if it dies immediately */
3499 signal(SIGPIPE, SIG_IGN);
3501 canary_pid = fork();
3502 if (canary_pid == 0) {
3503 char canary_binary[128], *lastslash;
3505 /* Reset signal handler */
3506 signal(SIGCHLD, SIG_DFL);
3507 signal(SIGPIPE, SIG_DFL);
3511 ast_close_fds_above_n(0);
3512 ast_set_priority(0);
3514 execlp("astcanary", "astcanary", canary_filename, (char *)NULL);
3516 /* If not found, try the same path as used to execute asterisk */
3517 ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
3518 if ((lastslash = strrchr(canary_binary, '/'))) {
3519 ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
3520 execl(canary_binary, "astcanary", canary_filename, (char *)NULL);
3523 /* Should never happen */
3525 } else if (canary_pid > 0) {
3526 pthread_t dont_care;
3528 ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
3531 /* Kill the canary when we exit */
3532 atexit(canary_exit);
3535 if (ast_event_init()) {
3536 printf("%s", term_quit());
3542 sigaddset(&sigs, SIGHUP);
3543 sigaddset(&sigs, SIGTERM);
3544 sigaddset(&sigs, SIGINT);
3545 sigaddset(&sigs, SIGPIPE);
3546 sigaddset(&sigs, SIGWINCH);
3547 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
3548 signal(SIGURG, urg_handler);
3549 signal(SIGINT, __quit_handler);
3550 signal(SIGTERM, __quit_handler);
3551 signal(SIGHUP, hup_handler);
3552 signal(SIGPIPE, SIG_IGN);
3554 /* ensure that the random number generators are seeded with a different value every time
3557 srand((unsigned int) getpid() + (unsigned int) time(NULL));
3558 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
3560 if (init_logger()) { /* Start logging subsystem */
3561 printf("%s", term_quit());
3565 threadstorage_init();
3569 ast_autoservice_init();
3571 if (ast_timing_init()) {
3572 printf("%s", term_quit());
3576 if (ast_ssl_init()) {
3577 printf("%s", term_quit());
3582 /* Load XML documentation. */
3583 ast_xmldoc_load_documentation();
3586 if (load_modules(1)) { /* Load modules, pre-load only */
3587 printf("%s", term_quit());
3591 if (dnsmgr_init()) { /* Initialize the DNS manager */
3592 printf("%s", term_quit());