2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2008, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
22 * \mainpage Asterisk -- The Open Source Telephony Project
24 * \par Developer Documentation for Asterisk
26 * This is the main developer documentation for Asterisk. It is
27 * generated by running "make progdocs" from the Asterisk source tree.
29 * In addition to the information available on the Asterisk source code,
30 * please see the appendices for information on coding guidelines,
31 * release management, commit policies, and more.
33 * \arg \ref AsteriskArchitecture
35 * \par Additional documentation
38 * \arg \ref ConfigFiles
40 * \section copyright Copyright and Author
42 * Copyright (C) 1999 - 2009, Digium, Inc.
43 * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
44 * of <a href="http://www.digium.com">Digium, Inc</a>.
46 * \author Mark Spencer <markster@digium.com>
47 * Also see \ref AstCREDITS
49 * See http://www.asterisk.org for more information about
50 * the Asterisk project. Please do not directly contact
51 * any of the maintainers of this project for assistance;
52 * the project provides a web site, mailing lists, and IRC
53 * channels for your use.
57 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
58 of PBX core functions and CLI interface.
64 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
66 #include "asterisk/_private.h"
68 #undef sched_setscheduler
77 #include <sys/resource.h>
81 #if defined(HAVE_SYSINFO)
82 #include <sys/sysinfo.h>
83 #elif defined(HAVE_SYSCTL)
84 #include <sys/param.h>
85 #include <sys/sysctl.h>
86 #if !defined(__OpenBSD__)
87 #include <sys/vmmeter.h>
88 #if defined(__FreeBSD__)
89 #include <vm/vm_param.h>
92 #if defined(HAVE_SWAPCTL)
99 int daemon(int, int); /* defined in libresolv of all places */
100 #include <sys/loadavg.h>
104 #include <sys/prctl.h>
106 #include <sys/capability.h>
107 #endif /* HAVE_CAP */
110 #include "asterisk/paths.h" /* we define here the variables so better agree on the prototype */
111 #include "asterisk/network.h"
112 #include "asterisk/cli.h"
113 #include "asterisk/channel.h"
114 #include "asterisk/features.h"
115 #include "asterisk/ulaw.h"
116 #include "asterisk/alaw.h"
117 #include "asterisk/callerid.h"
118 #include "asterisk/image.h"
119 #include "asterisk/tdd.h"
120 #include "asterisk/term.h"
121 #include "asterisk/manager.h"
122 #include "asterisk/cdr.h"
123 #include "asterisk/cel.h"
124 #include "asterisk/pbx.h"
125 #include "asterisk/enum.h"
126 #include "asterisk/http.h"
127 #include "asterisk/udptl.h"
128 #include "asterisk/app.h"
129 #include "asterisk/lock.h"
130 #include "asterisk/utils.h"
131 #include "asterisk/file.h"
132 #include "asterisk/io.h"
133 #include "editline/histedit.h"
134 #include "asterisk/config.h"
135 #include "asterisk/ast_version.h"
136 #include "asterisk/linkedlists.h"
137 #include "asterisk/devicestate.h"
138 #include "asterisk/module.h"
139 #include "asterisk/dsp.h"
140 #include "asterisk/buildinfo.h"
141 #include "asterisk/xmldoc.h"
142 #include "asterisk/poll-compat.h"
143 #include "asterisk/ccss.h"
144 #include "asterisk/test.h"
146 #include "../defaults.h"
149 #define AF_LOCAL AF_UNIX
150 #define PF_LOCAL PF_UNIX
153 #define AST_MAX_CONNECTS 128
156 /*! \brief Welcome message when starting a CLI interface */
157 #define WELCOME_MESSAGE \
158 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2010 Digium, Inc. and others.\n" \
159 "Created by Mark Spencer <markster@digium.com>\n" \
160 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
161 "This is free software, with components licensed under the GNU General Public\n" \
162 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
163 "certain conditions. Type 'core show license' for details.\n" \
164 "=========================================================================\n", ast_get_version()) \
166 /*! \defgroup main_options Main Configuration Options
167 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
168 * \arg \ref Config_ast "asterisk.conf"
169 * \note Some of them can be changed in the CLI
173 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
174 struct ast_flags ast_compat = { 0 };
176 int option_verbose; /*!< Verbosity level */
177 int option_debug; /*!< Debug level */
178 double option_maxload; /*!< Max load avg on system */
179 int option_maxcalls; /*!< Max number of active calls */
180 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
181 #if defined(HAVE_SYSINFO)
182 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
187 struct ast_eid ast_eid_default;
189 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
190 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
192 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
193 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
196 int fd; /*!< File descriptor */
197 int p[2]; /*!< Pipe */
198 pthread_t t; /*!< Thread of handler */
199 int mute; /*!< Is the console muted for logs */
200 int uid; /*!< Remote user ID. */
201 int gid; /*!< Remote group ID. */
202 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
207 AST_RWLIST_ENTRY(ast_atexit) list;
210 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
212 struct timeval ast_startuptime;
213 struct timeval ast_lastreloadtime;
215 static History *el_hist;
217 static char *remotehostname;
219 struct console consoles[AST_MAX_CONNECTS];
221 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
223 static int ast_el_add_history(char *);
224 static int ast_el_read_history(char *);
225 static int ast_el_write_history(char *);
228 char config_dir[PATH_MAX];
229 char module_dir[PATH_MAX];
230 char spool_dir[PATH_MAX];
231 char monitor_dir[PATH_MAX];
232 char var_dir[PATH_MAX];
233 char data_dir[PATH_MAX];
234 char log_dir[PATH_MAX];
235 char agi_dir[PATH_MAX];
236 char run_dir[PATH_MAX];
237 char key_dir[PATH_MAX];
239 char config_file[PATH_MAX];
240 char db_path[PATH_MAX];
241 char pid_path[PATH_MAX];
242 char socket_path[PATH_MAX];
243 char run_user[PATH_MAX];
244 char run_group[PATH_MAX];
245 char system_name[128];
248 static struct _cfg_paths cfg_paths;
250 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
251 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
252 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
253 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
254 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
255 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
256 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
257 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
258 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
259 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
260 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
262 const char *ast_config_AST_DB = cfg_paths.db_path;
263 const char *ast_config_AST_PID = cfg_paths.pid_path;
264 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
265 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
266 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
267 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
269 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
270 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
271 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
272 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
274 static char *_argv[256];
275 static int shuttingdown;
276 static int restartnow;
277 static pthread_t consolethread = AST_PTHREADT_NULL;
278 static int canary_pid = 0;
279 static char canary_filename[128];
281 static char randompool[256];
283 static int sig_alert_pipe[2] = { -1, -1 };
285 unsigned int need_reload:1;
286 unsigned int need_quit:1;
289 #if !defined(LOW_MEMORY)
290 struct file_version {
291 AST_RWLIST_ENTRY(file_version) list;
296 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
298 void ast_register_file_version(const char *file, const char *version)
300 struct file_version *new;
302 size_t version_length;
304 work = ast_strdupa(version);
305 work = ast_strip(ast_strip_quoted(work, "$", "$"));
306 version_length = strlen(work) + 1;
308 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
312 new->version = (char *) new + sizeof(*new);
313 memcpy(new->version, work, version_length);
314 AST_RWLIST_WRLOCK(&file_versions);
315 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
316 AST_RWLIST_UNLOCK(&file_versions);
319 void ast_unregister_file_version(const char *file)
321 struct file_version *find;
323 AST_RWLIST_WRLOCK(&file_versions);
324 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
325 if (!strcasecmp(find->file, file)) {
326 AST_RWLIST_REMOVE_CURRENT(list);
330 AST_RWLIST_TRAVERSE_SAFE_END;
331 AST_RWLIST_UNLOCK(&file_versions);
337 char *ast_complete_source_filename(const char *partial, int n)
339 struct file_version *find;
340 size_t len = strlen(partial);
344 AST_RWLIST_RDLOCK(&file_versions);
345 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
346 if (!strncasecmp(find->file, partial, len) && ++count > n) {
347 res = ast_strdup(find->file);
351 AST_RWLIST_UNLOCK(&file_versions);
355 /*! \brief Find version for given module name */
356 const char *ast_file_version_find(const char *file)
358 struct file_version *iterator;
360 AST_RWLIST_WRLOCK(&file_versions);
361 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, iterator, list) {
362 if (!strcasecmp(iterator->file, file))
365 AST_RWLIST_TRAVERSE_SAFE_END;
366 AST_RWLIST_UNLOCK(&file_versions);
368 return iterator->version;
374 struct thread_list_t {
375 AST_RWLIST_ENTRY(thread_list_t) list;
380 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
382 void ast_register_thread(char *name)
384 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
388 new->id = pthread_self();
389 new->name = name; /* steal the allocated memory for the thread name */
390 AST_RWLIST_WRLOCK(&thread_list);
391 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
392 AST_RWLIST_UNLOCK(&thread_list);
395 void ast_unregister_thread(void *id)
397 struct thread_list_t *x;
399 AST_RWLIST_WRLOCK(&thread_list);
400 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
401 if ((void *) x->id == id) {
402 AST_RWLIST_REMOVE_CURRENT(list);
406 AST_RWLIST_TRAVERSE_SAFE_END;
407 AST_RWLIST_UNLOCK(&thread_list);
414 /*! \brief Give an overview of core settings */
415 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
423 e->command = "core show settings";
424 e->usage = "Usage: core show settings\n"
425 " Show core misc settings";
431 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
433 ast_cli(a->fd, "\nPBX Core settings\n");
434 ast_cli(a->fd, "-----------------\n");
435 ast_cli(a->fd, " Version: %s\n", ast_get_version());
436 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
438 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
440 ast_cli(a->fd, " Maximum calls: Not set\n");
442 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
444 ast_cli(a->fd, " Maximum open file handles: Not set\n");
445 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
446 ast_cli(a->fd, " Debug level: %d\n", option_debug);
447 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
448 #if defined(HAVE_SYSINFO)
449 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
451 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
452 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
453 ast_cli(a->fd, " Startup time: %s\n", buf);
455 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
456 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
457 ast_cli(a->fd, " Last reload time: %s\n", buf);
459 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);
460 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
461 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
462 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
463 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
464 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
465 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
466 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
467 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
468 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
469 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
471 ast_cli(a->fd, "\n* Subsystems\n");
472 ast_cli(a->fd, " -------------\n");
473 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
474 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
475 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
476 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
478 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
480 ast_cli(a->fd, "\n* Directories\n");
481 ast_cli(a->fd, " -------------\n");
482 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
483 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
484 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
485 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
486 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
487 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
488 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
489 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
490 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
491 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
492 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
493 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
494 ast_cli(a->fd, "\n\n");
498 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
501 struct thread_list_t *cur;
504 e->command = "core show threads";
506 "Usage: core show threads\n"
507 " List threads currently active in the system.\n";
513 AST_RWLIST_RDLOCK(&thread_list);
514 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
515 ast_cli(a->fd, "%p %s\n", (void *)cur->id, cur->name);
518 AST_RWLIST_UNLOCK(&thread_list);
519 ast_cli(a->fd, "%d threads listed.\n", count);
523 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
525 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
526 * to be based on the new swapctl(2) system call.
528 static int swapmode(int *used, int *total)
530 struct swapent *swdev;
531 int nswap, rnswap, i;
533 nswap = swapctl(SWAP_NSWAP, 0, 0);
537 swdev = ast_calloc(nswap, sizeof(*swdev));
541 rnswap = swapctl(SWAP_STATS, swdev, nswap);
547 /* if rnswap != nswap, then what? */
549 /* Total things up */
551 for (i = 0; i < nswap; i++) {
552 if (swdev[i].se_flags & SWF_ENABLE) {
553 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
554 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
560 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
561 static int swapmode(int *used, int *total)
568 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
569 /*! \brief Give an overview of system statistics */
570 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
572 uint64_t physmem, freeram;
573 uint64_t freeswap = 0;
577 #if defined(HAVE_SYSINFO)
578 struct sysinfo sys_info;
580 uptime = sys_info.uptime / 3600;
581 physmem = sys_info.totalram * sys_info.mem_unit;
582 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
583 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
584 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
585 nprocs = sys_info.procs;
586 #elif defined(HAVE_SYSCTL)
587 static int pageshift;
588 struct vmtotal vmtotal;
589 struct timeval boottime;
591 int mib[2], pagesize, usedswap = 0;
593 /* calculate the uptime by looking at boottime */
596 mib[1] = KERN_BOOTTIME;
597 len = sizeof(boottime);
598 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
599 uptime = now - boottime.tv_sec;
601 uptime = uptime/3600;
602 /* grab total physical memory */
604 #if defined(HW_PHYSMEM64)
605 mib[1] = HW_PHYSMEM64;
609 len = sizeof(physmem);
610 sysctl(mib, 2, &physmem, &len, NULL, 0);
612 pagesize = getpagesize();
614 while (pagesize > 1) {
619 /* we only need the amount of log(2)1024 for our conversion */
625 len = sizeof(vmtotal);
626 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
627 freeram = (vmtotal.t_free << pageshift);
628 /* generate swap usage and totals */
629 swapmode(&usedswap, &totalswap);
630 freeswap = (totalswap - usedswap);
631 /* grab number of processes */
632 #if defined(__OpenBSD__)
634 mib[1] = KERN_NPROCS;
635 len = sizeof(nprocs);
636 sysctl(mib, 2, &nprocs, &len, NULL, 0);
642 e->command = "core show sysinfo";
644 "Usage: core show sysinfo\n"
645 " List current system information.\n";
651 ast_cli(a->fd, "\nSystem Statistics\n");
652 ast_cli(a->fd, "-----------------\n");
653 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
654 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
655 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
656 #if defined(HAVE_SYSINFO)
657 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
659 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
660 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
661 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
663 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
668 struct profile_entry {
670 uint64_t scale; /* if non-zero, values are scaled by this */
676 struct profile_data {
679 struct profile_entry e[0];
682 static struct profile_data *prof_data;
684 /*! \brief allocates a counter with a given name and scale.
685 * \return Returns the identifier of the counter.
687 int ast_add_profile(const char *name, uint64_t scale)
689 int l = sizeof(struct profile_data);
690 int n = 10; /* default entries */
692 if (prof_data == NULL) {
693 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
694 if (prof_data == NULL)
696 prof_data->entries = 0;
697 prof_data->max_size = n;
699 if (prof_data->entries >= prof_data->max_size) {
701 n = prof_data->max_size + 20;
702 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
706 prof_data->max_size = n;
708 n = prof_data->entries++;
709 prof_data->e[n].name = ast_strdup(name);
710 prof_data->e[n].value = 0;
711 prof_data->e[n].events = 0;
712 prof_data->e[n].mark = 0;
713 prof_data->e[n].scale = scale;
717 int64_t ast_profile(int i, int64_t delta)
719 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
721 if (prof_data->e[i].scale > 1)
722 delta /= prof_data->e[i].scale;
723 prof_data->e[i].value += delta;
724 prof_data->e[i].events++;
725 return prof_data->e[i].value;
728 /* The RDTSC instruction was introduced on the Pentium processor and is not
729 * implemented on certain clones, like the Cyrix 586. Hence, the previous
730 * expectation of __i386__ was in error. */
731 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
732 #if defined(__FreeBSD__)
733 #include <machine/cpufunc.h>
735 static __inline uint64_t
740 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
744 #else /* supply a dummy function on other platforms */
745 static __inline uint64_t
752 int64_t ast_mark(int i, int startstop)
754 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
757 prof_data->e[i].mark = rdtsc();
759 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
760 if (prof_data->e[i].scale > 1)
761 prof_data->e[i].mark /= prof_data->e[i].scale;
762 prof_data->e[i].value += prof_data->e[i].mark;
763 prof_data->e[i].events++;
765 return prof_data->e[i].mark;
768 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
769 max = prof_data->entries;\
770 if (a->argc > 3) { /* specific entries */ \
771 if (isdigit(a->argv[3][0])) { \
772 min = atoi(a->argv[3]); \
773 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
774 max = atoi(a->argv[4]); \
776 search = a->argv[3]; \
778 if (max > prof_data->entries) \
779 max = prof_data->entries;
781 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
784 const char *search = NULL;
787 e->command = "core show profile";
788 e->usage = "Usage: core show profile\n"
789 " show profile information";
795 if (prof_data == NULL)
798 DEFINE_PROFILE_MIN_MAX_VALUES;
799 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
800 prof_data->entries, prof_data->max_size);
801 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
802 "Value", "Average", "Name");
803 for (i = min; i < max; i++) {
804 struct profile_entry *entry = &prof_data->e[i];
805 if (!search || strstr(entry->name, search))
806 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
809 (long)entry->events, (long long)entry->value,
810 (long long)(entry->events ? entry->value / entry->events : entry->value),
816 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
819 const char *search = NULL;
822 e->command = "core clear profile";
823 e->usage = "Usage: core clear profile\n"
824 " clear profile information";
830 if (prof_data == NULL)
833 DEFINE_PROFILE_MIN_MAX_VALUES;
834 for (i= min; i < max; i++) {
835 if (!search || strstr(prof_data->e[i].name, search)) {
836 prof_data->e[i].value = 0;
837 prof_data->e[i].events = 0;
842 #undef DEFINE_PROFILE_MIN_MAX_VALUES
844 /*! \brief CLI command to list module versions */
845 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
847 #define FORMAT "%-25.25s %-40.40s\n"
848 struct file_version *iterator;
854 int matchlen, which = 0;
855 struct file_version *find;
859 e->command = "core show file version [like]";
861 "Usage: core show file version [like <pattern>]\n"
862 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
863 " Optional regular expression pattern is used to filter the file list.\n";
866 matchlen = strlen(a->word);
869 AST_RWLIST_RDLOCK(&file_versions);
870 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
871 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
872 ret = ast_strdup(find->file);
876 AST_RWLIST_UNLOCK(&file_versions);
883 if (!strcasecmp(a->argv[4], "like")) {
884 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
885 return CLI_SHOWUSAGE;
888 return CLI_SHOWUSAGE;
896 return CLI_SHOWUSAGE;
899 ast_cli(a->fd, FORMAT, "File", "Revision");
900 ast_cli(a->fd, FORMAT, "----", "--------");
901 AST_RWLIST_RDLOCK(&file_versions);
902 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
903 if (havename && strcasecmp(iterator->file, a->argv[4]))
906 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
909 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
914 AST_RWLIST_UNLOCK(&file_versions);
916 ast_cli(a->fd, "%d files listed.\n", count_files);
926 #endif /* ! LOW_MEMORY */
928 int ast_register_atexit(void (*func)(void))
930 struct ast_atexit *ae;
932 if (!(ae = ast_calloc(1, sizeof(*ae))))
937 ast_unregister_atexit(func);
939 AST_RWLIST_WRLOCK(&atexits);
940 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
941 AST_RWLIST_UNLOCK(&atexits);
946 void ast_unregister_atexit(void (*func)(void))
948 struct ast_atexit *ae = NULL;
950 AST_RWLIST_WRLOCK(&atexits);
951 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
952 if (ae->func == func) {
953 AST_RWLIST_REMOVE_CURRENT(list);
957 AST_RWLIST_TRAVERSE_SAFE_END;
958 AST_RWLIST_UNLOCK(&atexits);
963 /* Sending commands from consoles back to the daemon requires a terminating NULL */
964 static int fdsend(int fd, const char *s)
966 return write(fd, s, strlen(s) + 1);
969 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
970 static int fdprint(int fd, const char *s)
972 return write(fd, s, strlen(s));
975 /*! \brief NULL handler so we can collect the child exit status */
976 static void _null_sig_handler(int sig)
981 static struct sigaction null_sig_handler = {
982 .sa_handler = _null_sig_handler,
985 static struct sigaction ignore_sig_handler = {
986 .sa_handler = SIG_IGN,
989 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
990 /*! \brief Keep track of how many threads are currently trying to wait*() on
992 static unsigned int safe_system_level = 0;
993 static struct sigaction safe_system_prev_handler;
995 void ast_replace_sigchld(void)
999 ast_mutex_lock(&safe_system_lock);
1000 level = safe_system_level++;
1002 /* only replace the handler if it has not already been done */
1004 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1007 ast_mutex_unlock(&safe_system_lock);
1010 void ast_unreplace_sigchld(void)
1014 ast_mutex_lock(&safe_system_lock);
1015 level = --safe_system_level;
1017 /* only restore the handler if we are the last one */
1019 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1022 ast_mutex_unlock(&safe_system_lock);
1025 int ast_safe_system(const char *s)
1029 struct rusage rusage;
1032 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1033 ast_replace_sigchld();
1035 #ifdef HAVE_WORKING_FORK
1043 cap_t cap = cap_from_text("cap_net_admin-eip");
1045 if (cap_set_proc(cap)) {
1046 /* Careful with order! Logging cannot happen after we close FDs */
1047 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1051 #ifdef HAVE_WORKING_FORK
1052 if (ast_opt_high_priority)
1053 ast_set_priority(0);
1054 /* Close file descriptors and launch system command */
1055 ast_close_fds_above_n(STDERR_FILENO);
1057 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1059 } else if (pid > 0) {
1061 res = wait4(pid, &status, 0, &rusage);
1063 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1065 } else if (errno != EINTR)
1069 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1073 ast_unreplace_sigchld();
1074 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1081 void ast_console_toggle_loglevel(int fd, int level, int state)
1084 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1085 if (fd == consoles[x].fd) {
1086 consoles[x].levels[level] = state;
1093 * \brief mute or unmute a console from logging
1095 void ast_console_toggle_mute(int fd, int silent) {
1097 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1098 if (fd == consoles[x].fd) {
1099 if (consoles[x].mute) {
1100 consoles[x].mute = 0;
1102 ast_cli(fd, "Console is not muted anymore.\n");
1104 consoles[x].mute = 1;
1106 ast_cli(fd, "Console is muted.\n");
1111 ast_cli(fd, "Couldn't find remote console.\n");
1115 * \brief log the string to all attached console clients
1117 static void ast_network_puts_mutable(const char *string, int level)
1120 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1121 if (consoles[x].mute)
1123 if (consoles[x].fd > -1) {
1124 if (!consoles[x].levels[level])
1125 fdprint(consoles[x].p[1], string);
1131 * \brief log the string to the console, and all attached
1134 void ast_console_puts_mutable(const char *string, int level)
1136 fputs(string, stdout);
1138 ast_network_puts_mutable(string, level);
1142 * \brief write the string to all attached console clients
1144 static void ast_network_puts(const char *string)
1147 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1148 if (consoles[x].fd > -1)
1149 fdprint(consoles[x].p[1], string);
1154 * write the string to the console, and all attached
1157 void ast_console_puts(const char *string)
1159 fputs(string, stdout);
1161 ast_network_puts(string);
1164 static void network_verboser(const char *s)
1166 ast_network_puts_mutable(s, __LOG_VERBOSE);
1169 static pthread_t lthread;
1172 * \brief read() function supporting the reception of user credentials.
1174 * \param fd Socket file descriptor.
1175 * \param buffer Receive buffer.
1176 * \param size 'buffer' size.
1177 * \param con Console structure to set received credentials
1178 * \retval -1 on error
1179 * \retval the number of bytes received on success.
1181 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1183 #if defined(SO_PEERCRED)
1185 socklen_t len = sizeof(cred);
1187 #if defined(HAVE_GETPEEREID)
1195 result = read(fd, buffer, size);
1200 #if defined(SO_PEERCRED)
1201 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1206 #elif defined(HAVE_GETPEEREID)
1207 if (getpeereid(fd, &uid, &gid)) {
1219 static void *netconsole(void *vconsole)
1221 struct console *con = vconsole;
1222 char hostname[MAXHOSTNAMELEN] = "";
1225 struct pollfd fds[2];
1227 if (gethostname(hostname, sizeof(hostname)-1))
1228 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1229 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1230 fdprint(con->fd, tmp);
1232 fds[0].fd = con->fd;
1233 fds[0].events = POLLIN;
1235 fds[1].fd = con->p[0];
1236 fds[1].events = POLLIN;
1239 res = ast_poll(fds, 2, -1);
1242 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1245 if (fds[0].revents) {
1246 res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
1251 if (strncmp(tmp, "cli quit after ", 15) == 0) {
1252 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
1255 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
1257 if (fds[1].revents) {
1258 res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
1260 ast_log(LOG_ERROR, "read returned %d\n", res);
1263 res = write(con->fd, tmp, res);
1268 if (!ast_opt_hide_connect) {
1269 ast_verb(3, "Remote UNIX connection disconnected\n");
1279 static void *listener(void *unused)
1281 struct sockaddr_un sunaddr;
1286 struct pollfd fds[1];
1290 fds[0].fd = ast_socket;
1291 fds[0].events = POLLIN;
1292 s = ast_poll(fds, 1, -1);
1293 pthread_testcancel();
1296 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1299 len = sizeof(sunaddr);
1300 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1303 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1305 #if !defined(SO_PASSCRED)
1309 /* turn on socket credentials passing. */
1310 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1311 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1314 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1315 if (consoles[x].fd >= 0) {
1318 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1319 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1320 consoles[x].fd = -1;
1321 fdprint(s, "Server failed to create pipe\n");
1325 flags = fcntl(consoles[x].p[1], F_GETFL);
1326 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1328 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1329 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1330 to know if the user didn't send the credentials. */
1331 consoles[x].uid = -2;
1332 consoles[x].gid = -2;
1333 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1334 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1335 close(consoles[x].p[0]);
1336 close(consoles[x].p[1]);
1337 consoles[x].fd = -1;
1338 fdprint(s, "Server failed to spawn thread\n");
1343 if (x >= AST_MAX_CONNECTS) {
1344 fdprint(s, "No more connections allowed\n");
1345 ast_log(LOG_WARNING, "No more connections allowed\n");
1347 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1348 ast_verb(3, "Remote UNIX connection\n");
1356 static int ast_makesocket(void)
1358 struct sockaddr_un sunaddr;
1364 for (x = 0; x < AST_MAX_CONNECTS; x++)
1365 consoles[x].fd = -1;
1366 unlink(ast_config_AST_SOCKET);
1367 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1368 if (ast_socket < 0) {
1369 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1372 memset(&sunaddr, 0, sizeof(sunaddr));
1373 sunaddr.sun_family = AF_LOCAL;
1374 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1375 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1377 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1382 res = listen(ast_socket, 2);
1384 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1389 if (ast_register_verbose(network_verboser)) {
1390 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1393 ast_pthread_create_background(<hread, NULL, listener, NULL);
1395 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1397 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1398 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1403 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1405 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1406 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1411 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1412 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1414 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1417 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1419 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1420 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1426 static int ast_tryconnect(void)
1428 struct sockaddr_un sunaddr;
1430 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1431 if (ast_consock < 0) {
1432 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1435 memset(&sunaddr, 0, sizeof(sunaddr));
1436 sunaddr.sun_family = AF_LOCAL;
1437 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1438 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1447 /*! \brief Urgent handler
1449 Called by soft_hangup to interrupt the poll, read, or other
1450 system call. We don't actually need to do anything though.
1451 Remember: Cannot EVER ast_log from within a signal handler
1453 static void _urg_handler(int num)
1458 static struct sigaction urg_handler = {
1459 .sa_handler = _urg_handler,
1462 static void _hup_handler(int num)
1465 if (option_verbose > 1)
1466 printf("Received HUP signal -- Reloading configs\n");
1468 execvp(_argv[0], _argv);
1469 sig_flags.need_reload = 1;
1470 if (sig_alert_pipe[1] != -1) {
1471 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1472 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1477 static struct sigaction hup_handler = {
1478 .sa_handler = _hup_handler,
1481 static void _child_handler(int sig)
1483 /* Must not ever ast_log or ast_verbose within signal handler */
1487 * Reap all dead children -- not just one
1489 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1491 if (n == 0 && option_debug)
1492 printf("Huh? Child handler, but nobody there?\n");
1495 static struct sigaction child_handler = {
1496 .sa_handler = _child_handler,
1499 /*! \brief Set maximum open files */
1500 static void set_ulimit(int value)
1502 struct rlimit l = {0, 0};
1505 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1512 if (setrlimit(RLIMIT_NOFILE, &l)) {
1513 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1517 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1522 /*! \brief Set an X-term or screen title */
1523 static void set_title(char *text)
1525 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1526 fprintf(stdout, "\033]2;%s\007", text);
1529 static void set_icon(char *text)
1531 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1532 fprintf(stdout, "\033]1;%s\007", text);
1535 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1536 else. If your PBX has heavy activity on it, this is a good thing. */
1537 int ast_set_priority(int pri)
1539 struct sched_param sched;
1540 memset(&sched, 0, sizeof(sched));
1543 sched.sched_priority = 10;
1544 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1545 ast_log(LOG_WARNING, "Unable to set high priority\n");
1549 ast_verbose("Set to realtime thread\n");
1551 sched.sched_priority = 0;
1552 /* According to the manpage, these parameters can never fail. */
1553 sched_setscheduler(0, SCHED_OTHER, &sched);
1557 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1558 ast_log(LOG_WARNING, "Unable to set high priority\n");
1562 ast_verbose("Set to high priority\n");
1564 /* According to the manpage, these parameters can never fail. */
1565 setpriority(PRIO_PROCESS, 0, 0);
1571 static void ast_run_atexits(void)
1573 struct ast_atexit *ae;
1574 AST_RWLIST_RDLOCK(&atexits);
1575 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1579 AST_RWLIST_UNLOCK(&atexits);
1582 static void quit_handler(int num, int niceness, int safeshutdown, int restart)
1584 char filename[80] = "";
1587 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1588 ast_cdr_engine_term();
1592 /* Begin shutdown routine, hanging up active channels */
1593 ast_begin_shutdown(1);
1594 if (option_verbose && ast_opt_console)
1595 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1599 /* Wait up to 15 seconds for all channels to go away */
1602 if (!ast_active_channels())
1606 /* Sleep 1/10 of a second */
1611 ast_begin_shutdown(0);
1612 if (option_verbose && ast_opt_console)
1613 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1615 if (!ast_active_channels())
1623 if (!shuttingdown) {
1624 if (option_verbose && ast_opt_console)
1625 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1630 ast_module_shutdown();
1632 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1634 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1635 if (!ast_strlen_zero(filename))
1636 ast_el_write_history(filename);
1639 if (el_hist != NULL)
1640 history_end(el_hist);
1643 ast_verbose("Executing last minute cleanups\n");
1645 /* Called on exit */
1646 if (option_verbose && ast_opt_console)
1647 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1648 ast_debug(1, "Asterisk ending (%d).\n", num);
1649 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1650 if (ast_socket > -1) {
1651 pthread_cancel(lthread);
1654 unlink(ast_config_AST_SOCKET);
1656 if (ast_consock > -1)
1658 if (!ast_opt_remote)
1659 unlink(ast_config_AST_PID);
1660 printf("%s", term_quit());
1662 if (option_verbose || ast_opt_console)
1663 ast_verbose("Preparing for Asterisk restart...\n");
1664 /* Mark all FD's for closing on exec */
1665 for (x=3; x < 32768; x++) {
1666 fcntl(x, F_SETFD, FD_CLOEXEC);
1668 if (option_verbose || ast_opt_console)
1669 ast_verbose("Asterisk is now restarting...\n");
1675 /* If there is a consolethread running send it a SIGHUP
1676 so it can execvp, otherwise we can do it ourselves */
1677 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1678 pthread_kill(consolethread, SIGHUP);
1679 /* Give the signal handler some time to complete */
1682 execvp(_argv[0], _argv);
1691 static void __quit_handler(int num)
1694 sig_flags.need_quit = 1;
1695 if (sig_alert_pipe[1] != -1) {
1696 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1697 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1700 /* There is no need to restore the signal handler here, since the app
1701 * is going to exit */
1704 static void __remote_quit_handler(int num)
1706 sig_flags.need_quit = 1;
1709 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1713 /* Check for verboser preamble */
1718 if (!strncmp(s, cmp, strlen(cmp))) {
1719 c = s + strlen(cmp);
1720 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1726 static void console_verboser(const char *s)
1729 const char *c = NULL;
1731 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1732 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1733 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1734 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1746 /* Wake up a poll()ing console */
1747 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1748 pthread_kill(consolethread, SIGURG);
1751 static int ast_all_zeros(char *s)
1761 static void consolehandler(char *s)
1763 printf("%s", term_end());
1766 /* Called when readline data is available */
1767 if (!ast_all_zeros(s))
1768 ast_el_add_history(s);
1769 /* The real handler for bang */
1772 ast_safe_system(s+1);
1774 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1776 ast_cli_command(STDOUT_FILENO, s);
1779 static int remoteconsolehandler(char *s)
1783 /* Called when readline data is available */
1784 if (!ast_all_zeros(s))
1785 ast_el_add_history(s);
1786 /* The real handler for bang */
1789 ast_safe_system(s+1);
1791 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1794 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1795 (s[4] == '\0' || isspace(s[4]))) {
1796 quit_handler(0, 0, 0, 0);
1803 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1807 e->command = "core show version";
1809 "Usage: core show version\n"
1810 " Shows Asterisk version information.\n";
1817 return CLI_SHOWUSAGE;
1818 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1819 ast_get_version(), ast_build_user, ast_build_hostname,
1820 ast_build_machine, ast_build_os, ast_build_date);
1825 static int handle_quit(int fd, int argc, char *argv[])
1828 return RESULT_SHOWUSAGE;
1829 quit_handler(0, 0, 1, 0);
1830 return RESULT_SUCCESS;
1834 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1838 e->command = "core stop now";
1840 "Usage: core stop now\n"
1841 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1847 if (a->argc != e->args)
1848 return CLI_SHOWUSAGE;
1849 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1853 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1857 e->command = "core stop gracefully";
1859 "Usage: core stop gracefully\n"
1860 " Causes Asterisk to not accept new calls, and exit when all\n"
1861 " active calls have terminated normally.\n";
1867 if (a->argc != e->args)
1868 return CLI_SHOWUSAGE;
1869 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1873 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1877 e->command = "core stop when convenient";
1879 "Usage: core stop when convenient\n"
1880 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1886 if (a->argc != e->args)
1887 return CLI_SHOWUSAGE;
1888 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
1889 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1893 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1897 e->command = "core restart now";
1899 "Usage: core restart now\n"
1900 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1907 if (a->argc != e->args)
1908 return CLI_SHOWUSAGE;
1909 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1913 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1917 e->command = "core restart gracefully";
1919 "Usage: core restart gracefully\n"
1920 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1921 " restart when all active calls have ended.\n";
1927 if (a->argc != e->args)
1928 return CLI_SHOWUSAGE;
1929 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1933 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1937 e->command = "core restart when convenient";
1939 "Usage: core restart when convenient\n"
1940 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1946 if (a->argc != e->args)
1947 return CLI_SHOWUSAGE;
1948 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
1949 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1953 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1957 e->command = "core abort shutdown";
1959 "Usage: core abort shutdown\n"
1960 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1961 " call operations.\n";
1967 if (a->argc != e->args)
1968 return CLI_SHOWUSAGE;
1969 ast_cancel_shutdown();
1974 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1980 "Usage: !<command>\n"
1981 " Executes a given shell command\n";
1989 static const char warranty_lines[] = {
1993 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
1994 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
1995 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
1996 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
1997 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
1998 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
1999 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2000 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2001 "REPAIR OR CORRECTION.\n"
2003 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2004 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2005 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2006 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2007 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2008 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2009 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2010 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2011 "POSSIBILITY OF SUCH DAMAGES.\n"
2014 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2018 e->command = "core show warranty";
2020 "Usage: core show warranty\n"
2021 " Shows the warranty (if any) for this copy of Asterisk.\n";
2027 ast_cli(a->fd, "%s", warranty_lines);
2032 static const char license_lines[] = {
2034 "This program is free software; you can redistribute it and/or modify\n"
2035 "it under the terms of the GNU General Public License version 2 as\n"
2036 "published by the Free Software Foundation.\n"
2038 "This program also contains components licensed under other licenses.\n"
2041 "This program is distributed in the hope that it will be useful,\n"
2042 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2043 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2044 "GNU General Public License for more details.\n"
2046 "You should have received a copy of the GNU General Public License\n"
2047 "along with this program; if not, write to the Free Software\n"
2048 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2051 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2055 e->command = "core show license";
2057 "Usage: core show license\n"
2058 " Shows the license(s) for this copy of Asterisk.\n";
2064 ast_cli(a->fd, "%s", license_lines);
2069 #define ASTERISK_PROMPT "*CLI> "
2071 #define ASTERISK_PROMPT2 "%s*CLI> "
2073 static struct ast_cli_entry cli_asterisk[] = {
2074 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2075 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2076 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2077 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2078 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2079 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2080 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2081 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2082 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2083 AST_CLI_DEFINE(handle_version, "Display version info"),
2084 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2085 #if !defined(LOW_MEMORY)
2086 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2087 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2088 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2089 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2091 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2092 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2093 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2094 #endif /* ! LOW_MEMORY */
2097 static int ast_el_read_char(EditLine *editline, char *cp)
2101 struct pollfd fds[2];
2104 #define EL_BUF_SIZE 512
2105 char buf[EL_BUF_SIZE];
2109 fds[0].fd = ast_consock;
2110 fds[0].events = POLLIN;
2111 if (!ast_opt_exec) {
2112 fds[1].fd = STDIN_FILENO;
2113 fds[1].events = POLLIN;
2116 res = ast_poll(fds, max, -1);
2118 if (sig_flags.need_quit)
2122 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2126 if (!ast_opt_exec && fds[1].revents) {
2127 num_read = read(STDIN_FILENO, cp, 1);
2133 if (fds[0].revents) {
2135 res = read(ast_consock, buf, sizeof(buf) - 1);
2136 /* if the remote side disappears exit */
2138 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2139 if (!ast_opt_reconnect) {
2140 quit_handler(0, 0, 0, 0);
2143 int reconnects_per_second = 20;
2144 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2145 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2146 if (ast_tryconnect()) {
2147 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2148 printf("%s", term_quit());
2151 fdsend(ast_consock, "logger mute silent");
2153 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2156 usleep(1000000 / reconnects_per_second);
2158 if (tries >= 30 * reconnects_per_second) {
2159 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2160 quit_handler(0, 0, 0, 0);
2167 /* Strip preamble from asynchronous events, too */
2168 for (tmp = buf; *tmp; tmp++) {
2170 memmove(tmp, tmp + 1, strlen(tmp));
2176 /* Write over the CLI prompt */
2177 if (!ast_opt_exec && !lastpos) {
2178 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2181 if (write(STDOUT_FILENO, buf, res) < 0) {
2183 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2195 static struct ast_str *prompt = NULL;
2197 static char *cli_prompt(EditLine *editline)
2202 static int cli_prompt_changes = 0;
2207 if (prompt == NULL) {
2208 prompt = ast_str_create(100);
2209 } else if (!cli_prompt_changes) {
2210 return ast_str_buffer(prompt);
2212 ast_str_reset(prompt);
2215 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2217 struct timeval ts = ast_tvnow();
2218 while (*t != '\0') {
2220 char hostname[MAXHOSTNAMELEN] = "";
2222 struct ast_tm tm = { 0, };
2223 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2227 case 'C': /* color */
2229 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2230 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2232 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2233 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2237 /* If the color has been reset correctly, then there's no need to reset it later */
2238 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2240 case 'd': /* date */
2241 if (ast_localtime(&ts, &tm, NULL)) {
2242 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2243 ast_str_append(&prompt, 0, "%s", tmp);
2244 cli_prompt_changes++;
2247 case 'g': /* group */
2248 if ((gr = getgrgid(getgid()))) {
2249 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2252 case 'h': /* hostname */
2253 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2254 ast_str_append(&prompt, 0, "%s", hostname);
2256 ast_str_append(&prompt, 0, "%s", "localhost");
2259 case 'H': /* short hostname */
2260 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2262 if ((dotptr = strchr(hostname, '.'))) {
2265 ast_str_append(&prompt, 0, "%s", hostname);
2267 ast_str_append(&prompt, 0, "%s", "localhost");
2270 #ifdef HAVE_GETLOADAVG
2271 case 'l': /* load avg */
2273 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2275 getloadavg(list, 3);
2276 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2277 cli_prompt_changes++;
2281 case 's': /* Asterisk system name (from asterisk.conf) */
2282 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2284 case 't': /* time */
2285 if (ast_localtime(&ts, &tm, NULL)) {
2286 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2287 ast_str_append(&prompt, 0, "%s", tmp);
2288 cli_prompt_changes++;
2291 case 'u': /* username */
2292 if ((pw = getpwuid(getuid()))) {
2293 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2296 case '#': /* process console or remote? */
2297 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2299 case '%': /* literal % */
2300 ast_str_append(&prompt, 0, "%c", '%');
2302 case '\0': /* % is last character - prevent bug */
2307 ast_str_append(&prompt, 0, "%c", *t);
2312 /* Force colors back to normal at end */
2313 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2315 } else if (remotehostname) {
2316 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2318 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2321 return ast_str_buffer(prompt);
2324 static char **ast_el_strtoarr(char *buf)
2326 char **match_list = NULL, **match_list_tmp, *retstr;
2327 size_t match_list_len;
2331 while ( (retstr = strsep(&buf, " ")) != NULL) {
2333 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2335 if (matches + 1 >= match_list_len) {
2336 match_list_len <<= 1;
2337 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2338 match_list = match_list_tmp;
2341 ast_free(match_list);
2342 return (char **) NULL;
2346 match_list[matches++] = ast_strdup(retstr);
2350 return (char **) NULL;
2352 if (matches >= match_list_len) {
2353 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2354 match_list = match_list_tmp;
2357 ast_free(match_list);
2358 return (char **) NULL;
2362 match_list[matches] = (char *) NULL;
2367 static int ast_el_sort_compare(const void *i1, const void *i2)
2371 s1 = ((char **)i1)[0];
2372 s2 = ((char **)i2)[0];
2374 return strcasecmp(s1, s2);
2377 static int ast_cli_display_match_list(char **matches, int len, int max)
2379 int i, idx, limit, count;
2380 int screenwidth = 0;
2381 int numoutput = 0, numoutputline = 0;
2383 screenwidth = ast_get_termcols(STDOUT_FILENO);
2385 /* find out how many entries can be put on one line, with two spaces between strings */
2386 limit = screenwidth / (max + 2);
2390 /* how many lines of output */
2391 count = len / limit;
2392 if (count * limit < len)
2397 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2399 for (; count > 0; count--) {
2401 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2403 /* Don't print dupes */
2404 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2406 ast_free(matches[idx]);
2407 matches[idx] = NULL;
2413 fprintf(stdout, "%-*s ", max, matches[idx]);
2414 ast_free(matches[idx]);
2415 matches[idx] = NULL;
2417 if (numoutputline > 0)
2418 fprintf(stdout, "\n");
2425 static char *cli_complete(EditLine *editline, int ch)
2431 int retval = CC_ERROR;
2432 char buf[2048], savechr;
2435 LineInfo *lf = (LineInfo *)el_line(editline);
2437 savechr = *(char *)lf->cursor;
2438 *(char *)lf->cursor = '\0';
2439 ptr = (char *)lf->cursor;
2441 while (ptr > lf->buffer) {
2442 if (isspace(*ptr)) {
2450 len = lf->cursor - ptr;
2452 if (ast_opt_remote) {
2453 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2454 fdsend(ast_consock, buf);
2455 res = read(ast_consock, buf, sizeof(buf) - 1);
2457 nummatches = atoi(buf);
2459 if (nummatches > 0) {
2461 int mlen = 0, maxmbuf = 2048;
2462 /* Start with a 2048 byte buffer */
2463 if (!(mbuf = ast_malloc(maxmbuf))) {
2464 lf->cursor[0] = savechr;
2465 return (char *)(CC_ERROR);
2467 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2468 fdsend(ast_consock, buf);
2471 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2472 if (mlen + 1024 > maxmbuf) {
2473 /* Every step increment buffer 1024 bytes */
2475 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2476 lf->cursor[0] = savechr;
2477 return (char *)(CC_ERROR);
2480 /* Only read 1024 bytes at a time */
2481 res = read(ast_consock, mbuf + mlen, 1024);
2487 matches = ast_el_strtoarr(mbuf);
2490 matches = (char **) NULL;
2492 char **p, *oldbuf=NULL;
2494 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2495 for (p = matches; p && *p; p++) {
2496 if (!oldbuf || strcmp(*p,oldbuf))
2504 int matches_num, maxlen, match_len;
2506 if (matches[0][0] != '\0') {
2507 el_deletestr(editline, (int) len);
2508 el_insertstr(editline, matches[0]);
2509 retval = CC_REFRESH;
2512 if (nummatches == 1) {
2513 /* Found an exact match */
2514 el_insertstr(editline, " ");
2515 retval = CC_REFRESH;
2517 /* Must be more than one match */
2518 for (i = 1, maxlen = 0; matches[i]; i++) {
2519 match_len = strlen(matches[i]);
2520 if (match_len > maxlen)
2523 matches_num = i - 1;
2524 if (matches_num >1) {
2525 fprintf(stdout, "\n");
2526 ast_cli_display_match_list(matches, nummatches, maxlen);
2527 retval = CC_REDISPLAY;
2529 el_insertstr(editline," ");
2530 retval = CC_REFRESH;
2533 for (i = 0; matches[i]; i++)
2534 ast_free(matches[i]);
2538 lf->cursor[0] = savechr;
2540 return (char *)(long)retval;
2543 static int ast_el_initialize(void)
2546 char *editor = getenv("AST_EDITOR");
2550 if (el_hist != NULL)
2551 history_end(el_hist);
2553 el = el_init("asterisk", stdin, stdout, stderr);
2554 el_set(el, EL_PROMPT, cli_prompt);
2556 el_set(el, EL_EDITMODE, 1);
2557 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2558 el_hist = history_init();
2559 if (!el || !el_hist)
2562 /* setup history with 100 entries */
2563 history(el_hist, &ev, H_SETSIZE, 100);
2565 el_set(el, EL_HIST, history, el_hist);
2567 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2568 /* Bind <tab> to command completion */
2569 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2570 /* Bind ? to command completion */
2571 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2572 /* Bind ^D to redisplay */
2573 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2578 #define MAX_HISTORY_COMMAND_LENGTH 256
2580 static int ast_el_add_history(char *buf)
2584 if (el_hist == NULL || el == NULL)
2585 ast_el_initialize();
2586 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2588 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2591 static int ast_el_write_history(char *filename)
2595 if (el_hist == NULL || el == NULL)
2596 ast_el_initialize();
2598 return (history(el_hist, &ev, H_SAVE, filename));
2601 static int ast_el_read_history(char *filename)
2603 char buf[MAX_HISTORY_COMMAND_LENGTH];
2607 if (el_hist == NULL || el == NULL)
2608 ast_el_initialize();
2610 if ((f = fopen(filename, "r")) == NULL)
2614 if (!fgets(buf, sizeof(buf), f))
2616 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2618 if (ast_all_zeros(buf))
2620 if ((ret = ast_el_add_history(buf)) == -1)
2628 static void ast_remotecontrol(char *data)
2632 char filename[80] = "";
2637 char *stringp = NULL;
2642 memset(&sig_flags, 0, sizeof(sig_flags));
2643 signal(SIGINT, __remote_quit_handler);
2644 signal(SIGTERM, __remote_quit_handler);
2645 signal(SIGHUP, __remote_quit_handler);
2647 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2648 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2652 char prefix[] = "cli quit after ";
2653 char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
2654 sprintf(tmp, "%s%s", prefix, data);
2655 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2656 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2657 if (sig_flags.need_quit == 1) {
2663 hostname = strsep(&stringp, "/");
2664 cpid = strsep(&stringp, "/");
2665 version = strsep(&stringp, "\n");
2667 version = "<Version Unknown>";
2669 strsep(&stringp, ".");
2676 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2677 fdsend(ast_consock, tmp);
2678 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2679 fdsend(ast_consock, tmp);
2681 fdsend(ast_consock, "logger mute silent");
2683 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2686 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2688 fds.fd = ast_consock;
2689 fds.events = POLLIN;
2691 while (ast_poll(&fds, 1, 60000) > 0) {
2692 char buffer[512] = "", *curline = buffer, *nextline;
2693 int not_written = 1;
2695 if (sig_flags.need_quit == 1) {
2699 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
2704 if ((nextline = strchr(curline, '\n'))) {
2707 nextline = strchr(curline, '\0');
2710 /* Skip verbose lines */
2711 if (*curline != 127) {
2713 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2714 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
2718 } while (!ast_strlen_zero(curline));
2720 /* No non-verbose output in 60 seconds. */
2728 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2729 remotehostname = hostname;
2731 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2732 if (el_hist == NULL || el == NULL)
2733 ast_el_initialize();
2735 el_set(el, EL_GETCFN, ast_el_read_char);
2737 if (!ast_strlen_zero(filename))
2738 ast_el_read_history(filename);
2741 ebuf = (char *)el_gets(el, &num);
2743 if (sig_flags.need_quit == 1) {
2747 if (!ebuf && write(1, "", 1) < 0)
2750 if (!ast_strlen_zero(ebuf)) {
2751 if (ebuf[strlen(ebuf)-1] == '\n')
2752 ebuf[strlen(ebuf)-1] = '\0';
2753 if (!remoteconsolehandler(ebuf)) {
2754 /* Strip preamble from output */
2756 for (temp = ebuf; *temp; temp++) {
2758 memmove(temp, temp + 1, strlen(temp));
2762 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2764 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2770 printf("\nDisconnected from Asterisk server\n");
2773 static int show_version(void)
2775 printf("Asterisk %s\n", ast_get_version());
2779 static int show_cli_help(void) {
2780 printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
2781 printf("Usage: asterisk [OPTIONS]\n");
2782 printf("Valid Options:\n");
2783 printf(" -V Display version number and exit\n");
2784 printf(" -C <configfile> Use an alternate configuration file\n");
2785 printf(" -G <group> Run as a group other than the caller\n");
2786 printf(" -U <user> Run as a user other than the caller\n");
2787 printf(" -c Provide console CLI\n");
2788 printf(" -d Enable extra debugging\n");
2789 #if HAVE_WORKING_FORK
2790 printf(" -f Do not fork\n");
2791 printf(" -F Always fork\n");
2793 printf(" -g Dump core in case of a crash\n");
2794 printf(" -h This help screen\n");
2795 printf(" -i Initialize crypto keys at startup\n");
2796 printf(" -I Enable internal timing if DAHDI timer is available\n");
2797 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2798 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2799 printf(" -m Mute debugging and console output on the console\n");
2800 printf(" -n Disable console colorization\n");
2801 printf(" -p Run as pseudo-realtime thread\n");
2802 printf(" -q Quiet mode (suppress output)\n");
2803 printf(" -r Connect to Asterisk on this machine\n");
2804 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2805 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
2806 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2807 printf(" belong after they are done\n");
2808 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2809 printf(" of output to the CLI\n");
2810 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2811 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2812 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
2813 printf(" -W Adjust terminal colors to compensate for a light background\n");
2818 static void ast_readconfig(void)
2820 struct ast_config *cfg;
2821 struct ast_variable *v;
2822 char *config = DEFAULT_CONFIG_FILE;
2823 char hostname[MAXHOSTNAMELEN] = "";
2824 struct ast_flags config_flags = { 0 };
2826 unsigned int dbdir:1;
2827 unsigned int keydir:1;
2830 if (ast_opt_override_config) {
2831 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
2832 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
2833 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2835 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
2837 /* init with buildtime config */
2838 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2839 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2840 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2841 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
2842 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2843 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2844 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2845 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2846 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2847 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2848 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2849 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2850 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2852 ast_set_default_eid(&ast_eid_default);
2854 /* no asterisk.conf? no problem, use buildtime config! */
2855 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
2859 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2860 if (!strcasecmp(v->name, "astctlpermissions"))
2861 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2862 else if (!strcasecmp(v->name, "astctlowner"))
2863 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2864 else if (!strcasecmp(v->name, "astctlgroup"))
2865 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2866 else if (!strcasecmp(v->name, "astctl"))
2867 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2870 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2871 if (!strcasecmp(v->name, "astetcdir")) {
2872 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2873 } else if (!strcasecmp(v->name, "astspooldir")) {
2874 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2875 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
2876 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2877 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2879 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2880 } else if (!strcasecmp(v->name, "astdbdir")) {
2881 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2883 } else if (!strcasecmp(v->name, "astdatadir")) {
2884 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2886 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2887 } else if (!strcasecmp(v->name, "astkeydir")) {
2888 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2890 } else if (!strcasecmp(v->name, "astlogdir")) {
2891 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2892 } else if (!strcasecmp(v->name, "astagidir")) {
2893 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2894 } else if (!strcasecmp(v->name, "astrundir")) {
2895 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2896 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2897 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2898 } else if (!strcasecmp(v->name, "astmoddir")) {
2899 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2903 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2904 /* verbose level (-v at startup) */
2905 if (!strcasecmp(v->name, "verbose")) {
2906 option_verbose = atoi(v->value);
2907 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2908 } else if (!strcasecmp(v->name, "timestamp")) {
2909 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2910 /* whether or not to support #exec in config files */
2911 } else if (!strcasecmp(v->name, "execincludes")) {
2912 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2913 /* debug level (-d at startup) */
2914 } else if (!strcasecmp(v->name, "debug")) {
2916 if (sscanf(v->value, "%30d", &option_debug) != 1) {
2917 option_debug = ast_true(v->value);
2919 #if HAVE_WORKING_FORK
2920 /* Disable forking (-f at startup) */
2921 } else if (!strcasecmp(v->name, "nofork")) {
2922 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2923 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2924 } else if (!strcasecmp(v->name, "alwaysfork")) {
2925 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2927 /* Run quietly (-q at startup ) */
2928 } else if (!strcasecmp(v->name, "quiet")) {
2929 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2930 /* Run as console (-c at startup, implies nofork) */
2931 } else if (!strcasecmp(v->name, "console")) {
2932 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2933 /* Run with high priority if the O/S permits (-p at startup) */
2934 } else if (!strcasecmp(v->name, "highpriority")) {
2935 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2936 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2937 } else if (!strcasecmp(v->name, "initcrypto")) {
2938 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2939 /* Disable ANSI colors for console (-c at startup) */
2940 } else if (!strcasecmp(v->name, "nocolor")) {
2941 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2942 /* Disable some usage warnings for picky people :p */
2943 } else if (!strcasecmp(v->name, "dontwarn")) {
2944 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2945 /* Dump core in case of crash (-g) */
2946 } else if (!strcasecmp(v->name, "dumpcore")) {
2947 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2948 /* Cache recorded sound files to another directory during recording */
2949 } else if (!strcasecmp(v->name, "cache_record_files")) {
2950 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2951 /* Specify cache directory */
2952 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2953 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2954 /* Build transcode paths via SLINEAR, instead of directly */
2955 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2956 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2957 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2958 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2959 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2960 /* Enable internal timing */
2961 } else if (!strcasecmp(v->name, "internal_timing")) {
2962 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2963 } else if (!strcasecmp(v->name, "maxcalls")) {
2964 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2965 option_maxcalls = 0;
2967 } else if (!strcasecmp(v->name, "maxload")) {
2970 if (getloadavg(test, 1) == -1) {
2971 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2972 option_maxload = 0.0;
2973 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2974 option_maxload = 0.0;
2976 /* Set the maximum amount of open files */
2977 } else if (!strcasecmp(v->name, "maxfiles")) {
2978 option_maxfiles = atoi(v->value);
2979 set_ulimit(option_maxfiles);
2980 /* What user to run as */
2981 } else if (!strcasecmp(v->name, "runuser")) {
2982 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
2983 /* What group to run as */
2984 } else if (!strcasecmp(v->name, "rungroup")) {
2985 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
2986 } else if (!strcasecmp(v->name, "systemname")) {
2987 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
2988 } else if (!strcasecmp(v->name, "autosystemname")) {
2989 if (ast_true(v->value)) {
2990 if (!gethostname(hostname, sizeof(hostname) - 1))
2991 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
2993 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2994 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
2996 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2999 } else if (!strcasecmp(v->name, "languageprefix")) {
3000 ast_language_is_prefix = ast_true(v->value);
3001 } else if (!strcasecmp(v->name, "lockmode")) {
3002 if (!strcasecmp(v->value, "lockfile")) {
3003 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3004 } else if (!strcasecmp(v->value, "flock")) {
3005 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3007 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3008 "defaulting to 'lockfile'\n", v->value);
3009 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3011 #if defined(HAVE_SYSINFO)
3012 } else if (!strcasecmp(v->name, "minmemfree")) {
3013 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
3014 * if the amount of free memory falls below this watermark */
3015 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3016 option_minmemfree = 0;
3019 } else if (!strcasecmp(v->name, "entityid")) {
3020 struct ast_eid tmp_eid;
3021 if (!ast_str_to_eid(&tmp_eid, v->value)) {
3022 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3023 ast_eid_default = tmp_eid;
3025 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3026 } else if (!strcasecmp(v->name, "lightbackground")) {
3027 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3028 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3029 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3030 } else if (!strcasecmp(v->name, "hideconnect")) {
3031 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3032 } else if (!strcasecmp(v->name, "lockconfdir")) {
3033 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3036 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3038 if (sscanf(v->value, "%30f", &version) != 1) {
3039 ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3042 if (!strcasecmp(v->name, "app_set")) {
3043 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3044 } else if (!strcasecmp(v->name, "res_agi")) {
3045 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3046 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3047 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3050 ast_config_destroy(cfg);
3053 static void *monitor_sig_flags(void *unused)
3056 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3058 ast_poll(&p, 1, -1);
3059 if (sig_flags.need_reload) {
3060 sig_flags.need_reload = 0;
3061 ast_module_reload(NULL);
3063 if (sig_flags.need_quit) {
3064 sig_flags.need_quit = 0;
3065 quit_handler(0, 0, 1, 0);
3067 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3074 static void *canary_thread(void *unused)
3076 struct stat canary_stat;
3079 /* Give the canary time to sing */
3083 stat(canary_filename, &canary_stat);
3085 if (now.tv_sec > canary_stat.st_mtime + 60) {
3086 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");
3087 ast_set_priority(0);
3091 /* Check the canary once a minute */
3096 /* Used by libc's atexit(3) function */
3097 static void canary_exit(void)
3100 kill(canary_pid, SIGKILL);
3103 static void run_startup_commands(void)
3106 struct ast_config *cfg;
3107 struct ast_flags cfg_flags = { 0 };
3108 struct ast_variable *v;
3110 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3112 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3116 fd = open("/dev/null", O_RDWR);
3118 ast_config_destroy(cfg);
3122 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3123 if (ast_true(v->value))
3124 ast_cli_command(fd, v->name);
3128 ast_config_destroy(cfg);
3131 static void env_init(void)
3133 setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
3134 setenv("AST_BUILD_HOST", ast_build_hostname, 1);
3135 setenv("AST_BUILD_DATE", ast_build_date, 1);