2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2010, 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/translate.h"
115 #include "asterisk/features.h"
116 #include "asterisk/ulaw.h"
117 #include "asterisk/alaw.h"
118 #include "asterisk/callerid.h"
119 #include "asterisk/image.h"
120 #include "asterisk/tdd.h"
121 #include "asterisk/term.h"
122 #include "asterisk/manager.h"
123 #include "asterisk/cdr.h"
124 #include "asterisk/cel.h"
125 #include "asterisk/pbx.h"
126 #include "asterisk/enum.h"
127 #include "asterisk/http.h"
128 #include "asterisk/udptl.h"
129 #include "asterisk/app.h"
130 #include "asterisk/lock.h"
131 #include "asterisk/utils.h"
132 #include "asterisk/file.h"
133 #include "asterisk/io.h"
134 #include "editline/histedit.h"
135 #include "asterisk/config.h"
136 #include "asterisk/ast_version.h"
137 #include "asterisk/linkedlists.h"
138 #include "asterisk/devicestate.h"
139 #include "asterisk/module.h"
140 #include "asterisk/dsp.h"
141 #include "asterisk/buildinfo.h"
142 #include "asterisk/xmldoc.h"
143 #include "asterisk/poll-compat.h"
144 #include "asterisk/ccss.h"
145 #include "asterisk/test.h"
146 #include "asterisk/rtp_engine.h"
147 #include "asterisk/format.h"
148 #include "asterisk/aoc.h"
150 #include "../defaults.h"
153 #define AF_LOCAL AF_UNIX
154 #define PF_LOCAL PF_UNIX
157 #define AST_MAX_CONNECTS 128
160 /*! \brief Welcome message when starting a CLI interface */
161 #define WELCOME_MESSAGE \
162 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2010 Digium, Inc. and others.\n" \
163 "Created by Mark Spencer <markster@digium.com>\n" \
164 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
165 "This is free software, with components licensed under the GNU General Public\n" \
166 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
167 "certain conditions. Type 'core show license' for details.\n" \
168 "=========================================================================\n", ast_get_version()) \
170 /*! \defgroup main_options Main Configuration Options
171 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
172 * \arg \ref Config_ast "asterisk.conf"
173 * \note Some of them can be changed in the CLI
177 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
178 struct ast_flags ast_compat = { 0 };
180 int option_verbose; /*!< Verbosity level */
181 int option_debug; /*!< Debug level */
182 double option_maxload; /*!< Max load avg on system */
183 int option_maxcalls; /*!< Max number of active calls */
184 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
185 #if defined(HAVE_SYSINFO)
186 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
191 struct ast_eid ast_eid_default;
193 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
194 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
196 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
197 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
200 int fd; /*!< File descriptor */
201 int p[2]; /*!< Pipe */
202 pthread_t t; /*!< Thread of handler */
203 int mute; /*!< Is the console muted for logs */
204 int uid; /*!< Remote user ID. */
205 int gid; /*!< Remote group ID. */
206 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
211 AST_RWLIST_ENTRY(ast_atexit) list;
214 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
216 struct timeval ast_startuptime;
217 struct timeval ast_lastreloadtime;
219 static History *el_hist;
221 static char *remotehostname;
223 struct console consoles[AST_MAX_CONNECTS];
225 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
227 static int ast_el_add_history(char *);
228 static int ast_el_read_history(char *);
229 static int ast_el_write_history(char *);
232 char config_dir[PATH_MAX];
233 char module_dir[PATH_MAX];
234 char spool_dir[PATH_MAX];
235 char monitor_dir[PATH_MAX];
236 char var_dir[PATH_MAX];
237 char data_dir[PATH_MAX];
238 char log_dir[PATH_MAX];
239 char agi_dir[PATH_MAX];
240 char run_dir[PATH_MAX];
241 char key_dir[PATH_MAX];
243 char config_file[PATH_MAX];
244 char db_path[PATH_MAX];
245 char pid_path[PATH_MAX];
246 char socket_path[PATH_MAX];
247 char run_user[PATH_MAX];
248 char run_group[PATH_MAX];
249 char system_name[128];
252 static struct _cfg_paths cfg_paths;
254 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
255 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
256 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
257 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
258 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
259 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
260 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
261 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
262 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
263 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
264 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
266 const char *ast_config_AST_DB = cfg_paths.db_path;
267 const char *ast_config_AST_PID = cfg_paths.pid_path;
268 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
269 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
270 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
271 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
273 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
274 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
275 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
276 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
278 extern unsigned int ast_FD_SETSIZE;
280 static char *_argv[256];
281 static int shuttingdown;
282 static int restartnow;
283 static pthread_t consolethread = AST_PTHREADT_NULL;
284 static pthread_t mon_sig_flags;
285 static int canary_pid = 0;
286 static char canary_filename[128];
288 static char randompool[256];
290 static int sig_alert_pipe[2] = { -1, -1 };
292 unsigned int need_reload:1;
293 unsigned int need_quit:1;
296 #if !defined(LOW_MEMORY)
297 struct file_version {
298 AST_RWLIST_ENTRY(file_version) list;
303 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
305 void ast_register_file_version(const char *file, const char *version)
307 struct file_version *new;
309 size_t version_length;
311 work = ast_strdupa(version);
312 work = ast_strip(ast_strip_quoted(work, "$", "$"));
313 version_length = strlen(work) + 1;
315 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
319 new->version = (char *) new + sizeof(*new);
320 memcpy(new->version, work, version_length);
321 AST_RWLIST_WRLOCK(&file_versions);
322 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
323 AST_RWLIST_UNLOCK(&file_versions);
326 void ast_unregister_file_version(const char *file)
328 struct file_version *find;
330 AST_RWLIST_WRLOCK(&file_versions);
331 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
332 if (!strcasecmp(find->file, file)) {
333 AST_RWLIST_REMOVE_CURRENT(list);
337 AST_RWLIST_TRAVERSE_SAFE_END;
338 AST_RWLIST_UNLOCK(&file_versions);
344 char *ast_complete_source_filename(const char *partial, int n)
346 struct file_version *find;
347 size_t len = strlen(partial);
351 AST_RWLIST_RDLOCK(&file_versions);
352 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
353 if (!strncasecmp(find->file, partial, len) && ++count > n) {
354 res = ast_strdup(find->file);
358 AST_RWLIST_UNLOCK(&file_versions);
362 /*! \brief Find version for given module name */
363 const char *ast_file_version_find(const char *file)
365 struct file_version *iterator;
367 AST_RWLIST_WRLOCK(&file_versions);
368 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, iterator, list) {
369 if (!strcasecmp(iterator->file, file))
372 AST_RWLIST_TRAVERSE_SAFE_END;
373 AST_RWLIST_UNLOCK(&file_versions);
375 return iterator->version;
381 struct thread_list_t {
382 AST_RWLIST_ENTRY(thread_list_t) list;
388 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
390 void ast_register_thread(char *name)
392 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
396 new->id = pthread_self();
397 new->lwp = ast_get_tid();
398 new->name = name; /* steal the allocated memory for the thread name */
399 AST_RWLIST_WRLOCK(&thread_list);
400 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
401 AST_RWLIST_UNLOCK(&thread_list);
404 void ast_unregister_thread(void *id)
406 struct thread_list_t *x;
408 AST_RWLIST_WRLOCK(&thread_list);
409 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
410 if ((void *) x->id == id) {
411 AST_RWLIST_REMOVE_CURRENT(list);
415 AST_RWLIST_TRAVERSE_SAFE_END;
416 AST_RWLIST_UNLOCK(&thread_list);
423 /*! \brief Give an overview of core settings */
424 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
432 e->command = "core show settings";
433 e->usage = "Usage: core show settings\n"
434 " Show core misc settings";
440 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
442 ast_cli(a->fd, "\nPBX Core settings\n");
443 ast_cli(a->fd, "-----------------\n");
444 ast_cli(a->fd, " Version: %s\n", ast_get_version());
445 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
447 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
449 ast_cli(a->fd, " Maximum calls: Not set\n");
451 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
453 ast_cli(a->fd, " Maximum open file handles: Not set\n");
454 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
455 ast_cli(a->fd, " Debug level: %d\n", option_debug);
456 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
457 #if defined(HAVE_SYSINFO)
458 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
460 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
461 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
462 ast_cli(a->fd, " Startup time: %s\n", buf);
464 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
465 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
466 ast_cli(a->fd, " Last reload time: %s\n", buf);
468 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);
469 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
470 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
471 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
472 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
473 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
474 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
475 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
476 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
477 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
478 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
480 ast_cli(a->fd, "\n* Subsystems\n");
481 ast_cli(a->fd, " -------------\n");
482 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
483 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
484 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
485 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
487 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
489 ast_cli(a->fd, "\n* Directories\n");
490 ast_cli(a->fd, " -------------\n");
491 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
492 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
493 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
494 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
495 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
496 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
497 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
498 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
499 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
500 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
501 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
502 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
503 ast_cli(a->fd, "\n\n");
507 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
510 struct thread_list_t *cur;
513 e->command = "core show threads";
515 "Usage: core show threads\n"
516 " List threads currently active in the system.\n";
522 AST_RWLIST_RDLOCK(&thread_list);
523 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
524 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
527 AST_RWLIST_UNLOCK(&thread_list);
528 ast_cli(a->fd, "%d threads listed.\n", count);
532 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
534 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
535 * to be based on the new swapctl(2) system call.
537 static int swapmode(int *used, int *total)
539 struct swapent *swdev;
540 int nswap, rnswap, i;
542 nswap = swapctl(SWAP_NSWAP, 0, 0);
546 swdev = ast_calloc(nswap, sizeof(*swdev));
550 rnswap = swapctl(SWAP_STATS, swdev, nswap);
556 /* if rnswap != nswap, then what? */
558 /* Total things up */
560 for (i = 0; i < nswap; i++) {
561 if (swdev[i].se_flags & SWF_ENABLE) {
562 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
563 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
569 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
570 static int swapmode(int *used, int *total)
577 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
578 /*! \brief Give an overview of system statistics */
579 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
581 uint64_t physmem, freeram;
582 uint64_t freeswap = 0;
586 #if defined(HAVE_SYSINFO)
587 struct sysinfo sys_info;
589 uptime = sys_info.uptime / 3600;
590 physmem = sys_info.totalram * sys_info.mem_unit;
591 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
592 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
593 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
594 nprocs = sys_info.procs;
595 #elif defined(HAVE_SYSCTL)
596 static int pageshift;
597 struct vmtotal vmtotal;
598 struct timeval boottime;
600 int mib[2], pagesize, usedswap = 0;
602 /* calculate the uptime by looking at boottime */
605 mib[1] = KERN_BOOTTIME;
606 len = sizeof(boottime);
607 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
608 uptime = now - boottime.tv_sec;
610 uptime = uptime/3600;
611 /* grab total physical memory */
613 #if defined(HW_PHYSMEM64)
614 mib[1] = HW_PHYSMEM64;
618 len = sizeof(physmem);
619 sysctl(mib, 2, &physmem, &len, NULL, 0);
621 pagesize = getpagesize();
623 while (pagesize > 1) {
628 /* we only need the amount of log(2)1024 for our conversion */
634 len = sizeof(vmtotal);
635 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
636 freeram = (vmtotal.t_free << pageshift);
637 /* generate swap usage and totals */
638 swapmode(&usedswap, &totalswap);
639 freeswap = (totalswap - usedswap);
640 /* grab number of processes */
641 #if defined(__OpenBSD__)
643 mib[1] = KERN_NPROCS;
644 len = sizeof(nprocs);
645 sysctl(mib, 2, &nprocs, &len, NULL, 0);
651 e->command = "core show sysinfo";
653 "Usage: core show sysinfo\n"
654 " List current system information.\n";
660 ast_cli(a->fd, "\nSystem Statistics\n");
661 ast_cli(a->fd, "-----------------\n");
662 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
663 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
664 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
665 #if defined(HAVE_SYSINFO)
666 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
668 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
669 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
670 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
672 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
677 struct profile_entry {
679 uint64_t scale; /* if non-zero, values are scaled by this */
685 struct profile_data {
688 struct profile_entry e[0];
691 static struct profile_data *prof_data;
693 /*! \brief allocates a counter with a given name and scale.
694 * \return Returns the identifier of the counter.
696 int ast_add_profile(const char *name, uint64_t scale)
698 int l = sizeof(struct profile_data);
699 int n = 10; /* default entries */
701 if (prof_data == NULL) {
702 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
703 if (prof_data == NULL)
705 prof_data->entries = 0;
706 prof_data->max_size = n;
708 if (prof_data->entries >= prof_data->max_size) {
710 n = prof_data->max_size + 20;
711 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
715 prof_data->max_size = n;
717 n = prof_data->entries++;
718 prof_data->e[n].name = ast_strdup(name);
719 prof_data->e[n].value = 0;
720 prof_data->e[n].events = 0;
721 prof_data->e[n].mark = 0;
722 prof_data->e[n].scale = scale;
726 int64_t ast_profile(int i, int64_t delta)
728 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
730 if (prof_data->e[i].scale > 1)
731 delta /= prof_data->e[i].scale;
732 prof_data->e[i].value += delta;
733 prof_data->e[i].events++;
734 return prof_data->e[i].value;
737 /* The RDTSC instruction was introduced on the Pentium processor and is not
738 * implemented on certain clones, like the Cyrix 586. Hence, the previous
739 * expectation of __i386__ was in error. */
740 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
741 #if defined(__FreeBSD__)
742 #include <machine/cpufunc.h>
744 static __inline uint64_t
749 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
753 #else /* supply a dummy function on other platforms */
754 static __inline uint64_t
761 int64_t ast_mark(int i, int startstop)
763 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
766 prof_data->e[i].mark = rdtsc();
768 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
769 if (prof_data->e[i].scale > 1)
770 prof_data->e[i].mark /= prof_data->e[i].scale;
771 prof_data->e[i].value += prof_data->e[i].mark;
772 prof_data->e[i].events++;
774 return prof_data->e[i].mark;
777 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
778 max = prof_data->entries;\
779 if (a->argc > 3) { /* specific entries */ \
780 if (isdigit(a->argv[3][0])) { \
781 min = atoi(a->argv[3]); \
782 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
783 max = atoi(a->argv[4]); \
785 search = a->argv[3]; \
787 if (max > prof_data->entries) \
788 max = prof_data->entries;
790 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
793 const char *search = NULL;
796 e->command = "core show profile";
797 e->usage = "Usage: core show profile\n"
798 " show profile information";
804 if (prof_data == NULL)
807 DEFINE_PROFILE_MIN_MAX_VALUES;
808 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
809 prof_data->entries, prof_data->max_size);
810 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
811 "Value", "Average", "Name");
812 for (i = min; i < max; i++) {
813 struct profile_entry *entry = &prof_data->e[i];
814 if (!search || strstr(entry->name, search))
815 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
818 (long)entry->events, (long long)entry->value,
819 (long long)(entry->events ? entry->value / entry->events : entry->value),
825 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
828 const char *search = NULL;
831 e->command = "core clear profile";
832 e->usage = "Usage: core clear profile\n"
833 " clear profile information";
839 if (prof_data == NULL)
842 DEFINE_PROFILE_MIN_MAX_VALUES;
843 for (i= min; i < max; i++) {
844 if (!search || strstr(prof_data->e[i].name, search)) {
845 prof_data->e[i].value = 0;
846 prof_data->e[i].events = 0;
851 #undef DEFINE_PROFILE_MIN_MAX_VALUES
853 /*! \brief CLI command to list module versions */
854 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
856 #define FORMAT "%-25.25s %-40.40s\n"
857 struct file_version *iterator;
863 int matchlen, which = 0;
864 struct file_version *find;
868 e->command = "core show file version [like]";
870 "Usage: core show file version [like <pattern>]\n"
871 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
872 " Optional regular expression pattern is used to filter the file list.\n";
875 matchlen = strlen(a->word);
878 AST_RWLIST_RDLOCK(&file_versions);
879 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
880 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
881 ret = ast_strdup(find->file);
885 AST_RWLIST_UNLOCK(&file_versions);
892 if (!strcasecmp(a->argv[4], "like")) {
893 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
894 return CLI_SHOWUSAGE;
897 return CLI_SHOWUSAGE;
905 return CLI_SHOWUSAGE;
908 ast_cli(a->fd, FORMAT, "File", "Revision");
909 ast_cli(a->fd, FORMAT, "----", "--------");
910 AST_RWLIST_RDLOCK(&file_versions);
911 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
912 if (havename && strcasecmp(iterator->file, a->argv[4]))
915 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
918 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
923 AST_RWLIST_UNLOCK(&file_versions);
925 ast_cli(a->fd, "%d files listed.\n", count_files);
935 #endif /* ! LOW_MEMORY */
937 int ast_register_atexit(void (*func)(void))
939 struct ast_atexit *ae;
941 if (!(ae = ast_calloc(1, sizeof(*ae))))
946 ast_unregister_atexit(func);
948 AST_RWLIST_WRLOCK(&atexits);
949 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
950 AST_RWLIST_UNLOCK(&atexits);
955 void ast_unregister_atexit(void (*func)(void))
957 struct ast_atexit *ae = NULL;
959 AST_RWLIST_WRLOCK(&atexits);
960 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
961 if (ae->func == func) {
962 AST_RWLIST_REMOVE_CURRENT(list);
966 AST_RWLIST_TRAVERSE_SAFE_END;
967 AST_RWLIST_UNLOCK(&atexits);
972 /* Sending commands from consoles back to the daemon requires a terminating NULL */
973 static int fdsend(int fd, const char *s)
975 return write(fd, s, strlen(s) + 1);
978 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
979 static int fdprint(int fd, const char *s)
981 return write(fd, s, strlen(s));
984 /*! \brief NULL handler so we can collect the child exit status */
985 static void _null_sig_handler(int sig)
990 static struct sigaction null_sig_handler = {
991 .sa_handler = _null_sig_handler,
992 .sa_flags = SA_RESTART,
995 static struct sigaction ignore_sig_handler = {
996 .sa_handler = SIG_IGN,
999 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1000 /*! \brief Keep track of how many threads are currently trying to wait*() on
1001 * a child process */
1002 static unsigned int safe_system_level = 0;
1003 static struct sigaction safe_system_prev_handler;
1005 void ast_replace_sigchld(void)
1009 ast_mutex_lock(&safe_system_lock);
1010 level = safe_system_level++;
1012 /* only replace the handler if it has not already been done */
1014 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1017 ast_mutex_unlock(&safe_system_lock);
1020 void ast_unreplace_sigchld(void)
1024 ast_mutex_lock(&safe_system_lock);
1025 level = --safe_system_level;
1027 /* only restore the handler if we are the last one */
1029 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1032 ast_mutex_unlock(&safe_system_lock);
1035 int ast_safe_system(const char *s)
1039 struct rusage rusage;
1042 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1043 ast_replace_sigchld();
1045 #ifdef HAVE_WORKING_FORK
1053 cap_t cap = cap_from_text("cap_net_admin-eip");
1055 if (cap_set_proc(cap)) {
1056 /* Careful with order! Logging cannot happen after we close FDs */
1057 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1061 #ifdef HAVE_WORKING_FORK
1062 if (ast_opt_high_priority)
1063 ast_set_priority(0);
1064 /* Close file descriptors and launch system command */
1065 ast_close_fds_above_n(STDERR_FILENO);
1067 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1069 } else if (pid > 0) {
1071 res = wait4(pid, &status, 0, &rusage);
1073 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1075 } else if (errno != EINTR)
1079 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1083 ast_unreplace_sigchld();
1084 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1091 void ast_console_toggle_loglevel(int fd, int level, int state)
1094 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1095 if (fd == consoles[x].fd) {
1096 consoles[x].levels[level] = state;
1103 * \brief mute or unmute a console from logging
1105 void ast_console_toggle_mute(int fd, int silent) {
1107 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1108 if (fd == consoles[x].fd) {
1109 if (consoles[x].mute) {
1110 consoles[x].mute = 0;
1112 ast_cli(fd, "Console is not muted anymore.\n");
1114 consoles[x].mute = 1;
1116 ast_cli(fd, "Console is muted.\n");
1121 ast_cli(fd, "Couldn't find remote console.\n");
1125 * \brief log the string to all attached console clients
1127 static void ast_network_puts_mutable(const char *string, int level)
1130 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1131 if (consoles[x].mute)
1133 if (consoles[x].fd > -1) {
1134 if (!consoles[x].levels[level])
1135 fdprint(consoles[x].p[1], string);
1141 * \brief log the string to the console, and all attached
1144 void ast_console_puts_mutable(const char *string, int level)
1146 fputs(string, stdout);
1148 ast_network_puts_mutable(string, level);
1152 * \brief write the string to all attached console clients
1154 static void ast_network_puts(const char *string)
1157 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1158 if (consoles[x].fd > -1)
1159 fdprint(consoles[x].p[1], string);
1164 * write the string to the console, and all attached
1167 void ast_console_puts(const char *string)
1169 fputs(string, stdout);
1171 ast_network_puts(string);
1174 static void network_verboser(const char *s)
1176 ast_network_puts_mutable(s, __LOG_VERBOSE);
1179 static pthread_t lthread;
1182 * \brief read() function supporting the reception of user credentials.
1184 * \param fd Socket file descriptor.
1185 * \param buffer Receive buffer.
1186 * \param size 'buffer' size.
1187 * \param con Console structure to set received credentials
1188 * \retval -1 on error
1189 * \retval the number of bytes received on success.
1191 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1193 #if defined(SO_PEERCRED)
1195 socklen_t len = sizeof(cred);
1197 #if defined(HAVE_GETPEEREID)
1205 result = read(fd, buffer, size);
1210 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1211 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1214 #if defined(HAVE_STRUCT_UCRED_UID)
1217 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1220 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1222 #elif defined(HAVE_GETPEEREID)
1223 if (getpeereid(fd, &uid, &gid)) {
1235 static void *netconsole(void *vconsole)
1237 struct console *con = vconsole;
1238 char hostname[MAXHOSTNAMELEN] = "";
1241 struct pollfd fds[2];
1243 if (gethostname(hostname, sizeof(hostname)-1))
1244 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1245 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1246 fdprint(con->fd, tmp);
1248 fds[0].fd = con->fd;
1249 fds[0].events = POLLIN;
1251 fds[1].fd = con->p[0];
1252 fds[1].events = POLLIN;
1255 res = ast_poll(fds, 2, -1);
1258 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1261 if (fds[0].revents) {
1262 res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
1267 if (strncmp(tmp, "cli quit after ", 15) == 0) {
1268 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
1271 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
1273 if (fds[1].revents) {
1274 res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
1276 ast_log(LOG_ERROR, "read returned %d\n", res);
1279 res = write(con->fd, tmp, res);
1284 if (!ast_opt_hide_connect) {
1285 ast_verb(3, "Remote UNIX connection disconnected\n");
1295 static void *listener(void *unused)
1297 struct sockaddr_un sunaddr;
1302 struct pollfd fds[1];
1306 fds[0].fd = ast_socket;
1307 fds[0].events = POLLIN;
1308 s = ast_poll(fds, 1, -1);
1309 pthread_testcancel();
1312 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1315 len = sizeof(sunaddr);
1316 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1319 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1321 #if !defined(SO_PASSCRED)
1325 /* turn on socket credentials passing. */
1326 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1327 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1330 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1331 if (consoles[x].fd >= 0) {
1334 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1335 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1336 consoles[x].fd = -1;
1337 fdprint(s, "Server failed to create pipe\n");
1341 flags = fcntl(consoles[x].p[1], F_GETFL);
1342 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1344 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1345 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1346 to know if the user didn't send the credentials. */
1347 consoles[x].uid = -2;
1348 consoles[x].gid = -2;
1349 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1350 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1351 close(consoles[x].p[0]);
1352 close(consoles[x].p[1]);
1353 consoles[x].fd = -1;
1354 fdprint(s, "Server failed to spawn thread\n");
1359 if (x >= AST_MAX_CONNECTS) {
1360 fdprint(s, "No more connections allowed\n");
1361 ast_log(LOG_WARNING, "No more connections allowed\n");
1363 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1364 ast_verb(3, "Remote UNIX connection\n");
1372 static int ast_makesocket(void)
1374 struct sockaddr_un sunaddr;
1380 for (x = 0; x < AST_MAX_CONNECTS; x++)
1381 consoles[x].fd = -1;
1382 unlink(ast_config_AST_SOCKET);
1383 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1384 if (ast_socket < 0) {
1385 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1388 memset(&sunaddr, 0, sizeof(sunaddr));
1389 sunaddr.sun_family = AF_LOCAL;
1390 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1391 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1393 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1398 res = listen(ast_socket, 2);
1400 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1405 if (ast_register_verbose(network_verboser)) {
1406 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1409 ast_pthread_create_background(<hread, NULL, listener, NULL);
1411 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1413 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1414 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1419 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1421 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1422 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1427 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1428 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1430 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1433 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1435 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1436 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1442 static int ast_tryconnect(void)
1444 struct sockaddr_un sunaddr;
1446 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1447 if (ast_consock < 0) {
1448 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1451 memset(&sunaddr, 0, sizeof(sunaddr));
1452 sunaddr.sun_family = AF_LOCAL;
1453 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1454 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1463 /*! \brief Urgent handler
1465 Called by soft_hangup to interrupt the poll, read, or other
1466 system call. We don't actually need to do anything though.
1467 Remember: Cannot EVER ast_log from within a signal handler
1469 static void _urg_handler(int num)
1474 static struct sigaction urg_handler = {
1475 .sa_handler = _urg_handler,
1476 .sa_flags = SA_RESTART,
1479 static void _hup_handler(int num)
1482 if (option_verbose > 1)
1483 printf("Received HUP signal -- Reloading configs\n");
1485 execvp(_argv[0], _argv);
1486 sig_flags.need_reload = 1;
1487 if (sig_alert_pipe[1] != -1) {
1488 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1489 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1494 static struct sigaction hup_handler = {
1495 .sa_handler = _hup_handler,
1496 .sa_flags = SA_RESTART,
1499 static void _child_handler(int sig)
1501 /* Must not ever ast_log or ast_verbose within signal handler */
1505 * Reap all dead children -- not just one
1507 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1509 if (n == 0 && option_debug)
1510 printf("Huh? Child handler, but nobody there?\n");
1513 static struct sigaction child_handler = {
1514 .sa_handler = _child_handler,
1515 .sa_flags = SA_RESTART,
1518 /*! \brief Set maximum open files */
1519 static void set_ulimit(int value)
1521 struct rlimit l = {0, 0};
1524 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1531 if (setrlimit(RLIMIT_NOFILE, &l)) {
1532 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1536 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1541 /*! \brief Set an X-term or screen title */
1542 static void set_title(char *text)
1544 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1545 fprintf(stdout, "\033]2;%s\007", text);
1548 static void set_icon(char *text)
1550 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1551 fprintf(stdout, "\033]1;%s\007", text);
1554 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1555 else. If your PBX has heavy activity on it, this is a good thing. */
1556 int ast_set_priority(int pri)
1558 struct sched_param sched;
1559 memset(&sched, 0, sizeof(sched));
1562 sched.sched_priority = 10;
1563 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1564 ast_log(LOG_WARNING, "Unable to set high priority\n");
1568 ast_verbose("Set to realtime thread\n");
1570 sched.sched_priority = 0;
1571 /* According to the manpage, these parameters can never fail. */
1572 sched_setscheduler(0, SCHED_OTHER, &sched);
1576 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1577 ast_log(LOG_WARNING, "Unable to set high priority\n");
1581 ast_verbose("Set to high priority\n");
1583 /* According to the manpage, these parameters can never fail. */
1584 setpriority(PRIO_PROCESS, 0, 0);
1590 static void ast_run_atexits(void)
1592 struct ast_atexit *ae;
1593 AST_RWLIST_RDLOCK(&atexits);
1594 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1598 AST_RWLIST_UNLOCK(&atexits);
1601 static void quit_handler(int num, int niceness, int safeshutdown, int restart)
1603 char filename[80] = "";
1606 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1607 ast_cdr_engine_term();
1611 /* Begin shutdown routine, hanging up active channels */
1612 ast_begin_shutdown(1);
1613 if (option_verbose && ast_opt_console)
1614 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1618 /* Wait up to 15 seconds for all channels to go away */
1621 if (!ast_active_channels())
1625 /* Sleep 1/10 of a second */
1630 ast_begin_shutdown(0);
1631 if (option_verbose && ast_opt_console)
1632 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1634 if (!ast_active_channels())
1642 if (!shuttingdown) {
1643 if (option_verbose && ast_opt_console)
1644 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1649 ast_module_shutdown();
1651 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1652 pthread_t thisthread = pthread_self();
1653 if (getenv("HOME")) {
1654 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1656 if (!ast_strlen_zero(filename)) {
1657 ast_el_write_history(filename);
1659 if (consolethread == AST_PTHREADT_NULL || consolethread == thisthread || mon_sig_flags == thisthread) {
1660 /* Only end if we are the consolethread or signal handler, otherwise there's a race with that thread. */
1664 if (el_hist != NULL) {
1665 history_end(el_hist);
1670 ast_verbose("Executing last minute cleanups\n");
1672 /* Called on exit */
1673 if (option_verbose && ast_opt_console)
1674 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1675 ast_debug(1, "Asterisk ending (%d).\n", num);
1676 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1677 if (ast_socket > -1) {
1678 pthread_cancel(lthread);
1681 unlink(ast_config_AST_SOCKET);
1683 if (ast_consock > -1)
1685 if (!ast_opt_remote)
1686 unlink(ast_config_AST_PID);
1687 printf("%s", term_quit());
1689 if (option_verbose || ast_opt_console)
1690 ast_verbose("Preparing for Asterisk restart...\n");
1691 /* Mark all FD's for closing on exec */
1692 for (x=3; x < 32768; x++) {
1693 fcntl(x, F_SETFD, FD_CLOEXEC);
1695 if (option_verbose || ast_opt_console)
1696 ast_verbose("Asterisk is now restarting...\n");
1702 /* If there is a consolethread running send it a SIGHUP
1703 so it can execvp, otherwise we can do it ourselves */
1704 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1705 pthread_kill(consolethread, SIGHUP);
1706 /* Give the signal handler some time to complete */
1709 execvp(_argv[0], _argv);
1718 static void __quit_handler(int num)
1721 sig_flags.need_quit = 1;
1722 if (sig_alert_pipe[1] != -1) {
1723 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1724 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1727 /* There is no need to restore the signal handler here, since the app
1728 * is going to exit */
1731 static void __remote_quit_handler(int num)
1733 sig_flags.need_quit = 1;
1736 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1740 /* Check for verboser preamble */
1745 if (!strncmp(s, cmp, strlen(cmp))) {
1746 c = s + strlen(cmp);
1747 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1753 static void console_verboser(const char *s)
1756 const char *c = NULL;
1758 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1759 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1760 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1761 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1773 /* Wake up a poll()ing console */
1774 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1775 pthread_kill(consolethread, SIGURG);
1778 static int ast_all_zeros(char *s)
1788 static void consolehandler(char *s)
1790 printf("%s", term_end());
1793 /* Called when readline data is available */
1794 if (!ast_all_zeros(s))
1795 ast_el_add_history(s);
1796 /* The real handler for bang */
1799 ast_safe_system(s+1);
1801 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1803 ast_cli_command(STDOUT_FILENO, s);
1806 static int remoteconsolehandler(char *s)
1810 /* Called when readline data is available */
1811 if (!ast_all_zeros(s))
1812 ast_el_add_history(s);
1813 /* The real handler for bang */
1816 ast_safe_system(s+1);
1818 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1821 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1822 (s[4] == '\0' || isspace(s[4]))) {
1823 quit_handler(0, 0, 0, 0);
1830 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1834 e->command = "core show version";
1836 "Usage: core show version\n"
1837 " Shows Asterisk version information.\n";
1844 return CLI_SHOWUSAGE;
1845 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1846 ast_get_version(), ast_build_user, ast_build_hostname,
1847 ast_build_machine, ast_build_os, ast_build_date);
1852 static int handle_quit(int fd, int argc, char *argv[])
1855 return RESULT_SHOWUSAGE;
1856 quit_handler(0, 0, 1, 0);
1857 return RESULT_SUCCESS;
1861 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1865 e->command = "core stop now";
1867 "Usage: core stop now\n"
1868 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1874 if (a->argc != e->args)
1875 return CLI_SHOWUSAGE;
1876 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1880 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1884 e->command = "core stop gracefully";
1886 "Usage: core stop gracefully\n"
1887 " Causes Asterisk to not accept new calls, and exit when all\n"
1888 " active calls have terminated normally.\n";
1894 if (a->argc != e->args)
1895 return CLI_SHOWUSAGE;
1896 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1900 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1904 e->command = "core stop when convenient";
1906 "Usage: core stop when convenient\n"
1907 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1913 if (a->argc != e->args)
1914 return CLI_SHOWUSAGE;
1915 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
1916 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1920 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1924 e->command = "core restart now";
1926 "Usage: core restart now\n"
1927 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1934 if (a->argc != e->args)
1935 return CLI_SHOWUSAGE;
1936 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1940 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1944 e->command = "core restart gracefully";
1946 "Usage: core restart gracefully\n"
1947 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1948 " restart when all active calls have ended.\n";
1954 if (a->argc != e->args)
1955 return CLI_SHOWUSAGE;
1956 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1960 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1964 e->command = "core restart when convenient";
1966 "Usage: core restart when convenient\n"
1967 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1973 if (a->argc != e->args)
1974 return CLI_SHOWUSAGE;
1975 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
1976 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1980 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1984 e->command = "core abort shutdown";
1986 "Usage: core abort shutdown\n"
1987 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1988 " call operations.\n";
1994 if (a->argc != e->args)
1995 return CLI_SHOWUSAGE;
1996 ast_cancel_shutdown();
2001 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2007 "Usage: !<command>\n"
2008 " Executes a given shell command\n";
2016 static const char warranty_lines[] = {
2020 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2021 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2022 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2023 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2024 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2025 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2026 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2027 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2028 "REPAIR OR CORRECTION.\n"
2030 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2031 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2032 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2033 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2034 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2035 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2036 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2037 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2038 "POSSIBILITY OF SUCH DAMAGES.\n"
2041 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2045 e->command = "core show warranty";
2047 "Usage: core show warranty\n"
2048 " Shows the warranty (if any) for this copy of Asterisk.\n";
2054 ast_cli(a->fd, "%s", warranty_lines);
2059 static const char license_lines[] = {
2061 "This program is free software; you can redistribute it and/or modify\n"
2062 "it under the terms of the GNU General Public License version 2 as\n"
2063 "published by the Free Software Foundation.\n"
2065 "This program also contains components licensed under other licenses.\n"
2068 "This program is distributed in the hope that it will be useful,\n"
2069 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2070 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2071 "GNU General Public License for more details.\n"
2073 "You should have received a copy of the GNU General Public License\n"
2074 "along with this program; if not, write to the Free Software\n"
2075 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2078 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2082 e->command = "core show license";
2084 "Usage: core show license\n"
2085 " Shows the license(s) for this copy of Asterisk.\n";
2091 ast_cli(a->fd, "%s", license_lines);
2096 #define ASTERISK_PROMPT "*CLI> "
2098 #define ASTERISK_PROMPT2 "%s*CLI> "
2100 static struct ast_cli_entry cli_asterisk[] = {
2101 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2102 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2103 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2104 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2105 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2106 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2107 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2108 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2109 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2110 AST_CLI_DEFINE(handle_version, "Display version info"),
2111 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2112 #if !defined(LOW_MEMORY)
2113 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2114 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2115 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2116 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2118 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2119 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2120 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2121 #endif /* ! LOW_MEMORY */
2124 static int ast_el_read_char(EditLine *editline, char *cp)
2128 struct pollfd fds[2];
2131 #define EL_BUF_SIZE 512
2132 char buf[EL_BUF_SIZE];
2136 fds[0].fd = ast_consock;
2137 fds[0].events = POLLIN;
2138 if (!ast_opt_exec) {
2139 fds[1].fd = STDIN_FILENO;
2140 fds[1].events = POLLIN;
2143 res = ast_poll(fds, max, -1);
2145 if (sig_flags.need_quit)
2149 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2153 if (!ast_opt_exec && fds[1].revents) {
2154 num_read = read(STDIN_FILENO, cp, 1);
2160 if (fds[0].revents) {
2162 res = read(ast_consock, buf, sizeof(buf) - 1);
2163 /* if the remote side disappears exit */
2165 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2166 if (!ast_opt_reconnect) {
2167 quit_handler(0, 0, 0, 0);
2170 int reconnects_per_second = 20;
2171 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2172 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2173 if (ast_tryconnect()) {
2174 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2175 printf("%s", term_quit());
2178 fdsend(ast_consock, "logger mute silent");
2180 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2183 usleep(1000000 / reconnects_per_second);
2185 if (tries >= 30 * reconnects_per_second) {
2186 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2187 quit_handler(0, 0, 0, 0);
2194 /* Strip preamble from asynchronous events, too */
2195 for (tmp = buf; *tmp; tmp++) {
2197 memmove(tmp, tmp + 1, strlen(tmp));
2203 /* Write over the CLI prompt */
2204 if (!ast_opt_exec && !lastpos) {
2205 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2208 if (write(STDOUT_FILENO, buf, res) < 0) {
2210 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2222 static struct ast_str *prompt = NULL;
2224 static char *cli_prompt(EditLine *editline)
2229 static int cli_prompt_changes = 0;
2234 if (prompt == NULL) {
2235 prompt = ast_str_create(100);
2236 } else if (!cli_prompt_changes) {
2237 return ast_str_buffer(prompt);
2239 ast_str_reset(prompt);
2242 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2244 struct timeval ts = ast_tvnow();
2245 while (*t != '\0') {
2247 char hostname[MAXHOSTNAMELEN] = "";
2249 struct ast_tm tm = { 0, };
2250 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2254 case 'C': /* color */
2256 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2257 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2259 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2260 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2264 /* If the color has been reset correctly, then there's no need to reset it later */
2265 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2267 case 'd': /* date */
2268 if (ast_localtime(&ts, &tm, NULL)) {
2269 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2270 ast_str_append(&prompt, 0, "%s", tmp);
2271 cli_prompt_changes++;
2274 case 'g': /* group */
2275 if ((gr = getgrgid(getgid()))) {
2276 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2279 case 'h': /* hostname */
2280 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2281 ast_str_append(&prompt, 0, "%s", hostname);
2283 ast_str_append(&prompt, 0, "%s", "localhost");
2286 case 'H': /* short hostname */
2287 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2289 if ((dotptr = strchr(hostname, '.'))) {
2292 ast_str_append(&prompt, 0, "%s", hostname);
2294 ast_str_append(&prompt, 0, "%s", "localhost");
2297 #ifdef HAVE_GETLOADAVG
2298 case 'l': /* load avg */
2300 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2302 getloadavg(list, 3);
2303 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2304 cli_prompt_changes++;
2308 case 's': /* Asterisk system name (from asterisk.conf) */
2309 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2311 case 't': /* time */
2312 if (ast_localtime(&ts, &tm, NULL)) {
2313 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2314 ast_str_append(&prompt, 0, "%s", tmp);
2315 cli_prompt_changes++;
2318 case 'u': /* username */
2319 if ((pw = getpwuid(getuid()))) {
2320 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2323 case '#': /* process console or remote? */
2324 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2326 case '%': /* literal % */
2327 ast_str_append(&prompt, 0, "%c", '%');
2329 case '\0': /* % is last character - prevent bug */
2334 ast_str_append(&prompt, 0, "%c", *t);
2339 /* Force colors back to normal at end */
2340 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2342 } else if (remotehostname) {
2343 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2345 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2348 return ast_str_buffer(prompt);
2351 static char **ast_el_strtoarr(char *buf)
2353 char **match_list = NULL, **match_list_tmp, *retstr;
2354 size_t match_list_len;
2358 while ( (retstr = strsep(&buf, " ")) != NULL) {
2360 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2362 if (matches + 1 >= match_list_len) {
2363 match_list_len <<= 1;
2364 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2365 match_list = match_list_tmp;
2368 ast_free(match_list);
2369 return (char **) NULL;
2373 match_list[matches++] = ast_strdup(retstr);
2377 return (char **) NULL;
2379 if (matches >= match_list_len) {
2380 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2381 match_list = match_list_tmp;
2384 ast_free(match_list);
2385 return (char **) NULL;
2389 match_list[matches] = (char *) NULL;
2394 static int ast_el_sort_compare(const void *i1, const void *i2)
2398 s1 = ((char **)i1)[0];
2399 s2 = ((char **)i2)[0];
2401 return strcasecmp(s1, s2);
2404 static int ast_cli_display_match_list(char **matches, int len, int max)
2406 int i, idx, limit, count;
2407 int screenwidth = 0;
2408 int numoutput = 0, numoutputline = 0;
2410 screenwidth = ast_get_termcols(STDOUT_FILENO);
2412 /* find out how many entries can be put on one line, with two spaces between strings */
2413 limit = screenwidth / (max + 2);
2417 /* how many lines of output */
2418 count = len / limit;
2419 if (count * limit < len)
2424 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2426 for (; count > 0; count--) {
2428 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2430 /* Don't print dupes */
2431 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2433 ast_free(matches[idx]);
2434 matches[idx] = NULL;
2440 fprintf(stdout, "%-*s ", max, matches[idx]);
2441 ast_free(matches[idx]);
2442 matches[idx] = NULL;
2444 if (numoutputline > 0)
2445 fprintf(stdout, "\n");
2452 static char *cli_complete(EditLine *editline, int ch)
2458 int retval = CC_ERROR;
2459 char buf[2048], savechr;
2462 LineInfo *lf = (LineInfo *)el_line(editline);
2464 savechr = *(char *)lf->cursor;
2465 *(char *)lf->cursor = '\0';
2466 ptr = (char *)lf->cursor;
2468 while (ptr > lf->buffer) {
2469 if (isspace(*ptr)) {
2477 len = lf->cursor - ptr;
2479 if (ast_opt_remote) {
2480 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2481 fdsend(ast_consock, buf);
2482 res = read(ast_consock, buf, sizeof(buf) - 1);
2484 nummatches = atoi(buf);
2486 if (nummatches > 0) {
2488 int mlen = 0, maxmbuf = 2048;
2489 /* Start with a 2048 byte buffer */
2490 if (!(mbuf = ast_malloc(maxmbuf))) {
2491 lf->cursor[0] = savechr;
2492 return (char *)(CC_ERROR);
2494 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2495 fdsend(ast_consock, buf);
2498 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2499 if (mlen + 1024 > maxmbuf) {
2500 /* Every step increment buffer 1024 bytes */
2502 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2503 lf->cursor[0] = savechr;
2504 return (char *)(CC_ERROR);
2507 /* Only read 1024 bytes at a time */
2508 res = read(ast_consock, mbuf + mlen, 1024);
2514 matches = ast_el_strtoarr(mbuf);
2517 matches = (char **) NULL;
2519 char **p, *oldbuf=NULL;
2521 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2522 for (p = matches; p && *p; p++) {
2523 if (!oldbuf || strcmp(*p,oldbuf))
2531 int matches_num, maxlen, match_len;
2533 if (matches[0][0] != '\0') {
2534 el_deletestr(editline, (int) len);
2535 el_insertstr(editline, matches[0]);
2536 retval = CC_REFRESH;
2539 if (nummatches == 1) {
2540 /* Found an exact match */
2541 el_insertstr(editline, " ");
2542 retval = CC_REFRESH;
2544 /* Must be more than one match */
2545 for (i = 1, maxlen = 0; matches[i]; i++) {
2546 match_len = strlen(matches[i]);
2547 if (match_len > maxlen)
2550 matches_num = i - 1;
2551 if (matches_num >1) {
2552 fprintf(stdout, "\n");
2553 ast_cli_display_match_list(matches, nummatches, maxlen);
2554 retval = CC_REDISPLAY;
2556 el_insertstr(editline," ");
2557 retval = CC_REFRESH;
2560 for (i = 0; matches[i]; i++)
2561 ast_free(matches[i]);
2565 lf->cursor[0] = savechr;
2567 return (char *)(long)retval;
2570 static int ast_el_initialize(void)
2573 char *editor = getenv("AST_EDITOR");
2577 if (el_hist != NULL)
2578 history_end(el_hist);
2580 el = el_init("asterisk", stdin, stdout, stderr);
2581 el_set(el, EL_PROMPT, cli_prompt);
2583 el_set(el, EL_EDITMODE, 1);
2584 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2585 el_hist = history_init();
2586 if (!el || !el_hist)
2589 /* setup history with 100 entries */
2590 history(el_hist, &ev, H_SETSIZE, 100);
2592 el_set(el, EL_HIST, history, el_hist);
2594 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2595 /* Bind <tab> to command completion */
2596 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2597 /* Bind ? to command completion */
2598 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2599 /* Bind ^D to redisplay */
2600 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2605 #define MAX_HISTORY_COMMAND_LENGTH 256
2607 static int ast_el_add_history(char *buf)
2611 if (el_hist == NULL || el == NULL)
2612 ast_el_initialize();
2613 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2615 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2618 static int ast_el_write_history(char *filename)
2622 if (el_hist == NULL || el == NULL)
2623 ast_el_initialize();
2625 return (history(el_hist, &ev, H_SAVE, filename));
2628 static int ast_el_read_history(char *filename)
2630 char buf[MAX_HISTORY_COMMAND_LENGTH];
2634 if (el_hist == NULL || el == NULL)
2635 ast_el_initialize();
2637 if ((f = fopen(filename, "r")) == NULL)
2641 if (!fgets(buf, sizeof(buf), f))
2643 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2645 if (ast_all_zeros(buf))
2647 if ((ret = ast_el_add_history(buf)) == -1)
2655 static void ast_remotecontrol(char *data)
2659 char filename[80] = "";
2664 char *stringp = NULL;
2669 memset(&sig_flags, 0, sizeof(sig_flags));
2670 signal(SIGINT, __remote_quit_handler);
2671 signal(SIGTERM, __remote_quit_handler);
2672 signal(SIGHUP, __remote_quit_handler);
2674 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2675 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2679 char prefix[] = "cli quit after ";
2680 char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
2681 sprintf(tmp, "%s%s", prefix, data);
2682 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2683 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2684 if (sig_flags.need_quit == 1) {
2690 hostname = strsep(&stringp, "/");
2691 cpid = strsep(&stringp, "/");
2692 version = strsep(&stringp, "\n");
2694 version = "<Version Unknown>";
2696 strsep(&stringp, ".");
2703 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2704 fdsend(ast_consock, tmp);
2705 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2706 fdsend(ast_consock, tmp);
2708 fdsend(ast_consock, "logger mute silent");
2710 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2713 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2715 fds.fd = ast_consock;
2716 fds.events = POLLIN;
2718 while (ast_poll(&fds, 1, 60000) > 0) {
2719 char buffer[512] = "", *curline = buffer, *nextline;
2720 int not_written = 1;
2722 if (sig_flags.need_quit == 1) {
2726 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
2731 if ((nextline = strchr(curline, '\n'))) {
2734 nextline = strchr(curline, '\0');
2737 /* Skip verbose lines */
2738 if (*curline != 127) {
2740 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2741 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
2745 } while (!ast_strlen_zero(curline));
2747 /* No non-verbose output in 60 seconds. */
2755 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2756 remotehostname = hostname;
2758 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2759 if (el_hist == NULL || el == NULL)
2760 ast_el_initialize();
2762 el_set(el, EL_GETCFN, ast_el_read_char);
2764 if (!ast_strlen_zero(filename))
2765 ast_el_read_history(filename);
2768 ebuf = (char *)el_gets(el, &num);
2770 if (sig_flags.need_quit == 1) {
2774 if (!ebuf && write(1, "", 1) < 0)
2777 if (!ast_strlen_zero(ebuf)) {
2778 if (ebuf[strlen(ebuf)-1] == '\n')
2779 ebuf[strlen(ebuf)-1] = '\0';
2780 if (!remoteconsolehandler(ebuf)) {
2781 /* Strip preamble from output */
2783 for (temp = ebuf; *temp; temp++) {
2785 memmove(temp, temp + 1, strlen(temp));
2789 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2791 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2797 printf("\nDisconnected from Asterisk server\n");
2800 static int show_version(void)
2802 printf("Asterisk %s\n", ast_get_version());
2806 static int show_cli_help(void) {
2807 printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
2808 printf("Usage: asterisk [OPTIONS]\n");
2809 printf("Valid Options:\n");
2810 printf(" -V Display version number and exit\n");
2811 printf(" -C <configfile> Use an alternate configuration file\n");
2812 printf(" -G <group> Run as a group other than the caller\n");
2813 printf(" -U <user> Run as a user other than the caller\n");
2814 printf(" -c Provide console CLI\n");
2815 printf(" -d Enable extra debugging\n");
2816 #if HAVE_WORKING_FORK
2817 printf(" -f Do not fork\n");
2818 printf(" -F Always fork\n");
2820 printf(" -g Dump core in case of a crash\n");
2821 printf(" -h This help screen\n");
2822 printf(" -i Initialize crypto keys at startup\n");
2823 printf(" -I Enable internal timing if DAHDI timer is available\n");
2824 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2825 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2826 printf(" -m Mute debugging and console output on the console\n");
2827 printf(" -n Disable console colorization\n");
2828 printf(" -p Run as pseudo-realtime thread\n");
2829 printf(" -q Quiet mode (suppress output)\n");
2830 printf(" -r Connect to Asterisk on this machine\n");
2831 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2832 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
2833 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2834 printf(" belong after they are done\n");
2835 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2836 printf(" of output to the CLI\n");
2837 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2838 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2839 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
2840 printf(" -W Adjust terminal colors to compensate for a light background\n");
2845 static void ast_readconfig(void)
2847 struct ast_config *cfg;
2848 struct ast_variable *v;
2849 char *config = DEFAULT_CONFIG_FILE;
2850 char hostname[MAXHOSTNAMELEN] = "";
2851 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
2853 unsigned int dbdir:1;
2854 unsigned int keydir:1;
2857 if (ast_opt_override_config) {
2858 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
2859 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
2860 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2862 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
2864 /* init with buildtime config */
2865 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2866 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2867 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2868 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
2869 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2870 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2871 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2872 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2873 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2874 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2875 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2876 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2877 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2879 ast_set_default_eid(&ast_eid_default);
2881 /* no asterisk.conf? no problem, use buildtime config! */
2882 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
2886 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2887 if (!strcasecmp(v->name, "astctlpermissions"))
2888 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2889 else if (!strcasecmp(v->name, "astctlowner"))
2890 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2891 else if (!strcasecmp(v->name, "astctlgroup"))
2892 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2893 else if (!strcasecmp(v->name, "astctl"))
2894 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2897 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2898 if (!strcasecmp(v->name, "astetcdir")) {
2899 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2900 } else if (!strcasecmp(v->name, "astspooldir")) {
2901 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2902 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
2903 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2904 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2906 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2907 } else if (!strcasecmp(v->name, "astdbdir")) {
2908 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2910 } else if (!strcasecmp(v->name, "astdatadir")) {
2911 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2913 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2914 } else if (!strcasecmp(v->name, "astkeydir")) {
2915 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2917 } else if (!strcasecmp(v->name, "astlogdir")) {
2918 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2919 } else if (!strcasecmp(v->name, "astagidir")) {
2920 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2921 } else if (!strcasecmp(v->name, "astrundir")) {
2922 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2923 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2924 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2925 } else if (!strcasecmp(v->name, "astmoddir")) {
2926 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2930 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2931 /* verbose level (-v at startup) */
2932 if (!strcasecmp(v->name, "verbose")) {
2933 option_verbose = atoi(v->value);
2934 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2935 } else if (!strcasecmp(v->name, "timestamp")) {
2936 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2937 /* whether or not to support #exec in config files */
2938 } else if (!strcasecmp(v->name, "execincludes")) {
2939 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2940 /* debug level (-d at startup) */
2941 } else if (!strcasecmp(v->name, "debug")) {
2943 if (sscanf(v->value, "%30d", &option_debug) != 1) {
2944 option_debug = ast_true(v->value);
2946 #if HAVE_WORKING_FORK
2947 /* Disable forking (-f at startup) */
2948 } else if (!strcasecmp(v->name, "nofork")) {
2949 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2950 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2951 } else if (!strcasecmp(v->name, "alwaysfork")) {
2952 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2954 /* Run quietly (-q at startup ) */
2955 } else if (!strcasecmp(v->name, "quiet")) {
2956 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2957 /* Run as console (-c at startup, implies nofork) */
2958 } else if (!strcasecmp(v->name, "console")) {
2959 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2960 /* Run with high priority if the O/S permits (-p at startup) */
2961 } else if (!strcasecmp(v->name, "highpriority")) {
2962 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2963 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2964 } else if (!strcasecmp(v->name, "initcrypto")) {
2965 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2966 /* Disable ANSI colors for console (-c at startup) */
2967 } else if (!strcasecmp(v->name, "nocolor")) {
2968 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2969 /* Disable some usage warnings for picky people :p */
2970 } else if (!strcasecmp(v->name, "dontwarn")) {
2971 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2972 /* Dump core in case of crash (-g) */
2973 } else if (!strcasecmp(v->name, "dumpcore")) {
2974 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2975 /* Cache recorded sound files to another directory during recording */
2976 } else if (!strcasecmp(v->name, "cache_record_files")) {
2977 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2978 /* Specify cache directory */
2979 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2980 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2981 /* Build transcode paths via SLINEAR, instead of directly */
2982 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2983 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2984 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2985 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2986 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2987 /* Enable internal timing */
2988 } else if (!strcasecmp(v->name, "internal_timing")) {
2989 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2990 } else if (!strcasecmp(v->name, "maxcalls")) {
2991 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2992 option_maxcalls = 0;
2994 } else if (!strcasecmp(v->name, "maxload")) {
2997 if (getloadavg(test, 1) == -1) {
2998 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2999 option_maxload = 0.0;
3000 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3001 option_maxload = 0.0;
3003 /* Set the maximum amount of open files */
3004 } else if (!strcasecmp(v->name, "maxfiles")) {
3005 option_maxfiles = atoi(v->value);
3006 set_ulimit(option_maxfiles);
3007 /* What user to run as */
3008 } else if (!strcasecmp(v->name, "runuser")) {
3009 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3010 /* What group to run as */
3011 } else if (!strcasecmp(v->name, "rungroup")) {
3012 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3013 } else if (!strcasecmp(v->name, "systemname")) {
3014 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3015 } else if (!strcasecmp(v->name, "autosystemname")) {
3016 if (ast_true(v->value)) {
3017 if (!gethostname(hostname, sizeof(hostname) - 1))
3018 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3020 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3021 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3023 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3026 } else if (!strcasecmp(v->name, "languageprefix")) {
3027 ast_language_is_prefix = ast_true(v->value);
3028 } else if (!strcasecmp(v->name, "lockmode")) {
3029 if (!strcasecmp(v->value, "lockfile")) {
3030 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3031 } else if (!strcasecmp(v->value, "flock")) {
3032 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3034 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3035 "defaulting to 'lockfile'\n", v->value);
3036 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3038 #if defined(HAVE_SYSINFO)
3039 } else if (!strcasecmp(v->name, "minmemfree")) {
3040 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
3041 * if the amount of free memory falls below this watermark */
3042 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3043 option_minmemfree = 0;
3046 } else if (!strcasecmp(v->name, "entityid")) {
3047 struct ast_eid tmp_eid;
3048 if (!ast_str_to_eid(&tmp_eid, v->value)) {
3049 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3050 ast_eid_default = tmp_eid;
3052 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3053 } else if (!strcasecmp(v->name, "lightbackground")) {
3054 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3055 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3056 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3057 } else if (!strcasecmp(v->name, "hideconnect")) {
3058 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3059 } else if (!strcasecmp(v->name, "lockconfdir")) {
3060 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3063 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3065 if (sscanf(v->value, "%30f", &version) != 1) {
3066 ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3069 if (!strcasecmp(v->name, "app_set")) {
3070 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3071 } else if (!strcasecmp(v->name, "res_agi")) {
3072 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3073 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3074 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3077 ast_config_destroy(cfg);
3080 static void *monitor_sig_flags(void *unused)
3083 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3085 ast_poll(&p, 1, -1);
3086 if (sig_flags.need_reload) {
3087 sig_flags.need_reload = 0;
3088 ast_module_reload(NULL);
3090 if (sig_flags.need_quit) {
3091 sig_flags.need_quit = 0;
3092 quit_handler(0, 0, 1, 0);
3094 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3101 static void *canary_thread(void *unused)
3103 struct stat canary_stat;
3106 /* Give the canary time to sing */
3110 stat(canary_filename, &canary_stat);
3112 if (now.tv_sec > canary_stat.st_mtime + 60) {
3113 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");
3114 ast_set_priority(0);
3118 /* Check the canary once a minute */
3123 /* Used by libc's atexit(3) function */
3124 static void canary_exit(void)
3127 kill(canary_pid, SIGKILL);
3130 static void run_startup_commands(void)
3133 struct ast_config *cfg;
3134 struct ast_flags cfg_flags = { 0 };
3135 struct ast_variable *v;
3137 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3139 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3143 fd = open("/dev/null", O_RDWR);
3145 ast_config_destroy(cfg);
3149 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3150 if (ast_true(v->value))
3151 ast_cli_command(fd, v->name);
3155 ast_config_destroy(cfg);
3158 static void env_init(void)
3160 setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
3161 setenv("AST_BUILD_HOST", ast_build_hostname, 1);
3162 setenv("AST_BUILD_DATE", ast_build_date, 1);
3163 setenv("AST_BUILD_KERNEL", ast_build_kernel, 1);
3164 setenv("AST_BUILD_MACHINE", ast_build_machine, 1);
3165 setenv("AST_BUILD_OS", ast_build_os, 1);
3166 setenv("AST_BUILD_USER", ast_build_user, 1);
3167 setenv("AST_VERSION", ast_get_version(), 1);
3170 int main(int argc, char *argv[])
3173 char filename[80] = "";
3174 char hostname[MAXHOSTNAMELEN] = "";
3181 int isroot = 1, rundir_exists = 0;
3183 const char *runuser = NULL, *rungroup = NULL;
3184 char *remotesock = NULL;
3185 int moduleresult; /*!< Result from the module load subsystem */
3188 /* Remember original args for restart */
3189 if (argc > ARRAY_LEN(_argv) - 1) {
3190 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
3191 argc = ARRAY_LEN(_argv) - 1;
3193 for (x = 0; x < argc; x++)
3200 /* if the progname is rasterisk consider it a remote console */
3201 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
3202 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3204 if (gethostname(hostname, sizeof(hostname)-1))
3205 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
3206 ast_mainpid = getpid();
3210 ast_builtins_init();
3218 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3219 /* Check for options */
3220 while ((c = getopt(argc, argv, "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:")) != -1) {
3221 /*!\note Please keep the ordering here to alphabetical, capital letters
3222 * first. This will make it easier in the future to select unused
3223 * option flags for new features. */
3225 case 'B': /* Force black background */
3226 ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3227 ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
3230 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES);
3233 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
3234 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
3237 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3241 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3243 #if defined(HAVE_SYSINFO)
3245 if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3246 option_minmemfree = 0;
3250 #if HAVE_WORKING_FORK
3252 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
3255 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3259 rungroup = ast_strdupa(optarg);
3262 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
3268 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
3271 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
3274 if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3275 option_maxload = 0.0;
3279 if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3280 option_maxcalls = 0;
3284 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
3287 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
3290 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
3293 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
3296 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
3299 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3302 remotesock = ast_strdupa(optarg);
3305 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
3308 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
3311 runuser = ast_strdupa(optarg);
3318 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3320 case 'W': /* White background */
3321 ast_set_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
3322 ast_clear_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3325 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC | AST_OPT_FLAG_NO_COLOR);
3326 xarg = ast_strdupa(optarg);
3333 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
3334 if (ast_register_verbose(console_verboser)) {
3335 ast_log(LOG_WARNING, "Unable to register console verboser?\n");
3340 if (ast_opt_console && !option_verbose)
3341 ast_verbose("[ Booting...\n");
3343 /* For remote connections, change the name of the remote connection.
3344 * We do this for the benefit of init scripts (which need to know if/when
3345 * the main asterisk process has died yet). */
3346 if (ast_opt_remote) {
3347 strcpy(argv[0], "rasterisk");
3348 for (x = 1; x < argc; x++) {
3349 argv[x] = argv[0] + 10;
3353 if (ast_opt_console && !option_verbose) {
3354 ast_verbose("[ Reading Master Configuration ]\n");
3360 if (ast_opt_remote && remotesock != NULL)
3361 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
3363 if (!ast_language_is_prefix && !ast_opt_remote)
3364 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");
3366 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
3367 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
3368 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
3371 if (ast_opt_dump_core) {
3372 memset(&l, 0, sizeof(l));
3373 l.rlim_cur = RLIM_INFINITY;
3374 l.rlim_max = RLIM_INFINITY;
3375 if (setrlimit(RLIMIT_CORE, &l)) {
3376 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
3380 if (getrlimit(RLIMIT_NOFILE, &l)) {
3381 ast_log(LOG_WARNING, "Unable to check file descriptor limit: %s\n", strerror(errno));
3384 #if !defined(CONFIGURE_RAN_AS_ROOT)
3385 /* Check if select(2) will run with more file descriptors */
3389 struct timeval tv = { 0, };
3391 if (l.rlim_cur <= FD_SETSIZE) {
3392 /* The limit of select()able FDs is irrelevant, because we'll never
3393 * open one that high. */
3397 if (!(fd = open("/dev/null", O_RDONLY))) {
3398 ast_log(LOG_ERROR, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
3399 break; /* XXX Should we exit() here? XXX */
3402 fd2 = (l.rlim_cur > sizeof(readers) * 8 ? sizeof(readers) * 8 : l.rlim_cur) - 1;
3403 if (dup2(fd, fd2) < 0) {
3404 ast_log(LOG_WARNING, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
3410 FD_SET(fd2, &readers);
3411 if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
3412 ast_log(LOG_WARNING, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
3414 ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
3418 #elif defined(HAVE_VARIABLE_FDSET)
3419 ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
3420 #endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
3422 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
3423 rungroup = ast_config_AST_RUN_GROUP;
3424 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
3425 runuser = ast_config_AST_RUN_USER;
3427 /* Must install this signal handler up here to ensure that if the canary
3428 * fails to execute that it doesn't kill the Asterisk process.
3430 sigaction(SIGCHLD, &child_handler, NULL);
3432 /* It's common on some platforms to clear /var/run at boot. Create the
3433 * socket file directory before we drop privileges. */
3434 if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
3435 if (errno == EEXIST) {
3438 ast_log(LOG_WARNING, "Unable to create socket file directory. Remote consoles will not be able to connect! (%s)\n", strerror(x));
3445 ast_set_priority(ast_opt_high_priority);
3448 if (isroot && rungroup) {
3450 gr = getgrnam(rungroup);
3452 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
3455 if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
3456 ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
3458 if (setgid(gr->gr_gid)) {
3459 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
3462 if (setgroups(0, NULL)) {
3463 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
3467 ast_verbose("Running as group '%s'\n", rungroup);
3470 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
3473 #endif /* HAVE_CAP */
3475 pw = getpwnam(runuser);
3477 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
3480 if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
3481 ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
3484 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
3485 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
3488 #endif /* HAVE_CAP */
3489 if (!isroot && pw->pw_uid != geteuid()) {
3490 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
3494 if (setgid(pw->pw_gid)) {
3495 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
3498 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
3499 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
3503 if (setuid(pw->pw_uid)) {
3504 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
3508 ast_verbose("Running as user '%s'\n", runuser);
3513 cap = cap_from_text("cap_net_admin=eip");
3515 if (cap_set_proc(cap))
3516 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
3519 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
3521 #endif /* HAVE_CAP */
3524 #endif /* __CYGWIN__ */
3527 if (geteuid() && ast_opt_dump_core) {
3528 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
3529 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
3535 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
3536 #if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
3537 #define eaccess euidaccess
3540 if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
3541 ast_log(LOG_ERROR, "Unable to access the running directory (%s). Changing to '/' for compatibility.\n", strerror(errno));
3542 /* If we cannot access the CWD, then we couldn't dump core anyway,
3543 * so chdir("/") won't break anything. */
3545 /* chdir(/) should never fail, so this ends up being a no-op */
3546 ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
3549 #endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
3550 if (!ast_opt_no_fork && !ast_opt_dump_core) {
3551 /* Backgrounding, but no cores, so chdir won't break anything. */
3553 ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
3559 printf("%s", term_end());
3562 if (ast_opt_console && !option_verbose)
3563 ast_verbose("[ Initializing Custom Configuration Options ]\n");
3564 /* custom config setup */
3565 register_config_cli();
3568 if (ast_opt_console) {
3569 if (el_hist == NULL || el == NULL)
3570 ast_el_initialize();
3572 if (!ast_strlen_zero(filename))
3573 ast_el_read_history(filename);
3576 if (ast_tryconnect()) {
3577 /* One is already running */
3578 if (ast_opt_remote) {
3580 ast_remotecontrol(xarg);
3581 quit_handler(0, 0, 0, 0);
3584 printf("%s", term_quit());
3585 ast_remotecontrol(NULL);
3586 quit_handler(0, 0, 0, 0);
3589 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);