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 totalswap = 0, freeswap = 0;
576 #if defined(HAVE_SYSINFO)
577 struct sysinfo sys_info;
579 uptime = sys_info.uptime / 3600;
580 physmem = sys_info.totalram * sys_info.mem_unit;
581 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
582 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
583 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
584 nprocs = sys_info.procs;
585 #elif defined(HAVE_SYSCTL)
586 static int pageshift;
587 struct vmtotal vmtotal;
588 struct timeval boottime;
590 int mib[2], pagesize, usedswap = 0;
592 /* calculate the uptime by looking at boottime */
595 mib[1] = KERN_BOOTTIME;
596 len = sizeof(boottime);
597 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
598 uptime = now - boottime.tv_sec;
600 uptime = uptime/3600;
601 /* grab total physical memory */
603 #if defined(HW_PHYSMEM64)
604 mib[1] = HW_PHYSMEM64;
608 len = sizeof(physmem);
609 sysctl(mib, 2, &physmem, &len, NULL, 0);
611 pagesize = getpagesize();
613 while (pagesize > 1) {
618 /* we only need the amount of log(2)1024 for our conversion */
624 len = sizeof(vmtotal);
625 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
626 freeram = (vmtotal.t_free << pageshift);
627 /* generate swap usage and totals */
628 swapmode(&usedswap, &totalswap);
629 freeswap = (totalswap - usedswap);
630 /* grab number of processes */
631 #if defined(__OpenBSD__)
633 mib[1] = KERN_NPROCS;
634 len = sizeof(nprocs);
635 sysctl(mib, 2, &nprocs, &len, NULL, 0);
641 e->command = "core show sysinfo";
643 "Usage: core show sysinfo\n"
644 " List current system information.\n";
650 ast_cli(a->fd, "\nSystem Statistics\n");
651 ast_cli(a->fd, "-----------------\n");
652 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
653 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
654 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
655 #if defined(HAVE_SYSINFO)
656 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
658 ast_cli(a->fd, " Total Swap Space: %" PRIu64 " KiB\n", totalswap);
659 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
660 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
665 struct profile_entry {
667 uint64_t scale; /* if non-zero, values are scaled by this */
673 struct profile_data {
676 struct profile_entry e[0];
679 static struct profile_data *prof_data;
681 /*! \brief allocates a counter with a given name and scale.
682 * \return Returns the identifier of the counter.
684 int ast_add_profile(const char *name, uint64_t scale)
686 int l = sizeof(struct profile_data);
687 int n = 10; /* default entries */
689 if (prof_data == NULL) {
690 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
691 if (prof_data == NULL)
693 prof_data->entries = 0;
694 prof_data->max_size = n;
696 if (prof_data->entries >= prof_data->max_size) {
698 n = prof_data->max_size + 20;
699 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
703 prof_data->max_size = n;
705 n = prof_data->entries++;
706 prof_data->e[n].name = ast_strdup(name);
707 prof_data->e[n].value = 0;
708 prof_data->e[n].events = 0;
709 prof_data->e[n].mark = 0;
710 prof_data->e[n].scale = scale;
714 int64_t ast_profile(int i, int64_t delta)
716 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
718 if (prof_data->e[i].scale > 1)
719 delta /= prof_data->e[i].scale;
720 prof_data->e[i].value += delta;
721 prof_data->e[i].events++;
722 return prof_data->e[i].value;
725 /* The RDTSC instruction was introduced on the Pentium processor and is not
726 * implemented on certain clones, like the Cyrix 586. Hence, the previous
727 * expectation of __i386__ was in error. */
728 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
729 #if defined(__FreeBSD__)
730 #include <machine/cpufunc.h>
732 static __inline uint64_t
737 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
741 #else /* supply a dummy function on other platforms */
742 static __inline uint64_t
749 int64_t ast_mark(int i, int startstop)
751 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
754 prof_data->e[i].mark = rdtsc();
756 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
757 if (prof_data->e[i].scale > 1)
758 prof_data->e[i].mark /= prof_data->e[i].scale;
759 prof_data->e[i].value += prof_data->e[i].mark;
760 prof_data->e[i].events++;
762 return prof_data->e[i].mark;
765 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
766 max = prof_data->entries;\
767 if (a->argc > 3) { /* specific entries */ \
768 if (isdigit(a->argv[3][0])) { \
769 min = atoi(a->argv[3]); \
770 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
771 max = atoi(a->argv[4]); \
773 search = a->argv[3]; \
775 if (max > prof_data->entries) \
776 max = prof_data->entries;
778 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
781 const char *search = NULL;
784 e->command = "core show profile";
785 e->usage = "Usage: core show profile\n"
786 " show profile information";
792 if (prof_data == NULL)
795 DEFINE_PROFILE_MIN_MAX_VALUES;
796 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
797 prof_data->entries, prof_data->max_size);
798 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
799 "Value", "Average", "Name");
800 for (i = min; i < max; i++) {
801 struct profile_entry *entry = &prof_data->e[i];
802 if (!search || strstr(entry->name, search))
803 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
806 (long)entry->events, (long long)entry->value,
807 (long long)(entry->events ? entry->value / entry->events : entry->value),
813 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
816 const char *search = NULL;
819 e->command = "core clear profile";
820 e->usage = "Usage: core clear profile\n"
821 " clear profile information";
827 if (prof_data == NULL)
830 DEFINE_PROFILE_MIN_MAX_VALUES;
831 for (i= min; i < max; i++) {
832 if (!search || strstr(prof_data->e[i].name, search)) {
833 prof_data->e[i].value = 0;
834 prof_data->e[i].events = 0;
839 #undef DEFINE_PROFILE_MIN_MAX_VALUES
841 /*! \brief CLI command to list module versions */
842 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
844 #define FORMAT "%-25.25s %-40.40s\n"
845 struct file_version *iterator;
851 int matchlen, which = 0;
852 struct file_version *find;
856 e->command = "core show file version [like]";
858 "Usage: core show file version [like <pattern>]\n"
859 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
860 " Optional regular expression pattern is used to filter the file list.\n";
863 matchlen = strlen(a->word);
866 AST_RWLIST_RDLOCK(&file_versions);
867 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
868 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
869 ret = ast_strdup(find->file);
873 AST_RWLIST_UNLOCK(&file_versions);
880 if (!strcasecmp(a->argv[4], "like")) {
881 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
882 return CLI_SHOWUSAGE;
885 return CLI_SHOWUSAGE;
893 return CLI_SHOWUSAGE;
896 ast_cli(a->fd, FORMAT, "File", "Revision");
897 ast_cli(a->fd, FORMAT, "----", "--------");
898 AST_RWLIST_RDLOCK(&file_versions);
899 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
900 if (havename && strcasecmp(iterator->file, a->argv[4]))
903 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
906 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
911 AST_RWLIST_UNLOCK(&file_versions);
913 ast_cli(a->fd, "%d files listed.\n", count_files);
923 #endif /* ! LOW_MEMORY */
925 int ast_register_atexit(void (*func)(void))
927 struct ast_atexit *ae;
929 if (!(ae = ast_calloc(1, sizeof(*ae))))
934 ast_unregister_atexit(func);
936 AST_RWLIST_WRLOCK(&atexits);
937 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
938 AST_RWLIST_UNLOCK(&atexits);
943 void ast_unregister_atexit(void (*func)(void))
945 struct ast_atexit *ae = NULL;
947 AST_RWLIST_WRLOCK(&atexits);
948 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
949 if (ae->func == func) {
950 AST_RWLIST_REMOVE_CURRENT(list);
954 AST_RWLIST_TRAVERSE_SAFE_END;
955 AST_RWLIST_UNLOCK(&atexits);
960 /* Sending commands from consoles back to the daemon requires a terminating NULL */
961 static int fdsend(int fd, const char *s)
963 return write(fd, s, strlen(s) + 1);
966 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
967 static int fdprint(int fd, const char *s)
969 return write(fd, s, strlen(s));
972 /*! \brief NULL handler so we can collect the child exit status */
973 static void _null_sig_handler(int sig)
978 static struct sigaction null_sig_handler = {
979 .sa_handler = _null_sig_handler,
982 static struct sigaction ignore_sig_handler = {
983 .sa_handler = SIG_IGN,
986 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
987 /*! \brief Keep track of how many threads are currently trying to wait*() on
989 static unsigned int safe_system_level = 0;
990 static struct sigaction safe_system_prev_handler;
992 void ast_replace_sigchld(void)
996 ast_mutex_lock(&safe_system_lock);
997 level = safe_system_level++;
999 /* only replace the handler if it has not already been done */
1001 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1004 ast_mutex_unlock(&safe_system_lock);
1007 void ast_unreplace_sigchld(void)
1011 ast_mutex_lock(&safe_system_lock);
1012 level = --safe_system_level;
1014 /* only restore the handler if we are the last one */
1016 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1019 ast_mutex_unlock(&safe_system_lock);
1022 int ast_safe_system(const char *s)
1026 struct rusage rusage;
1029 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1030 ast_replace_sigchld();
1032 #ifdef HAVE_WORKING_FORK
1040 cap_t cap = cap_from_text("cap_net_admin-eip");
1042 if (cap_set_proc(cap)) {
1043 /* Careful with order! Logging cannot happen after we close FDs */
1044 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1048 #ifdef HAVE_WORKING_FORK
1049 if (ast_opt_high_priority)
1050 ast_set_priority(0);
1051 /* Close file descriptors and launch system command */
1052 ast_close_fds_above_n(STDERR_FILENO);
1054 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1056 } else if (pid > 0) {
1058 res = wait4(pid, &status, 0, &rusage);
1060 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1062 } else if (errno != EINTR)
1066 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1070 ast_unreplace_sigchld();
1071 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1078 void ast_console_toggle_loglevel(int fd, int level, int state)
1081 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1082 if (fd == consoles[x].fd) {
1083 consoles[x].levels[level] = state;
1090 * \brief mute or unmute a console from logging
1092 void ast_console_toggle_mute(int fd, int silent) {
1094 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1095 if (fd == consoles[x].fd) {
1096 if (consoles[x].mute) {
1097 consoles[x].mute = 0;
1099 ast_cli(fd, "Console is not muted anymore.\n");
1101 consoles[x].mute = 1;
1103 ast_cli(fd, "Console is muted.\n");
1108 ast_cli(fd, "Couldn't find remote console.\n");
1112 * \brief log the string to all attached console clients
1114 static void ast_network_puts_mutable(const char *string, int level)
1117 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1118 if (consoles[x].mute)
1120 if (consoles[x].fd > -1) {
1121 if (!consoles[x].levels[level])
1122 fdprint(consoles[x].p[1], string);
1128 * \brief log the string to the console, and all attached
1131 void ast_console_puts_mutable(const char *string, int level)
1133 fputs(string, stdout);
1135 ast_network_puts_mutable(string, level);
1139 * \brief write the string to all attached console clients
1141 static void ast_network_puts(const char *string)
1144 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1145 if (consoles[x].fd > -1)
1146 fdprint(consoles[x].p[1], string);
1151 * write the string to the console, and all attached
1154 void ast_console_puts(const char *string)
1156 fputs(string, stdout);
1158 ast_network_puts(string);
1161 static void network_verboser(const char *s)
1163 ast_network_puts_mutable(s, __LOG_VERBOSE);
1166 static pthread_t lthread;
1169 * \brief read() function supporting the reception of user credentials.
1171 * \param fd Socket file descriptor.
1172 * \param buffer Receive buffer.
1173 * \param size 'buffer' size.
1174 * \param con Console structure to set received credentials
1175 * \retval -1 on error
1176 * \retval the number of bytes received on success.
1178 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1180 #if defined(SO_PEERCRED)
1182 socklen_t len = sizeof(cred);
1184 #if defined(HAVE_GETPEEREID)
1192 result = read(fd, buffer, size);
1197 #if defined(SO_PEERCRED)
1198 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1203 #elif defined(HAVE_GETPEEREID)
1204 if (getpeereid(fd, &uid, &gid)) {
1216 static void *netconsole(void *vconsole)
1218 struct console *con = vconsole;
1219 char hostname[MAXHOSTNAMELEN] = "";
1222 struct pollfd fds[2];
1224 if (gethostname(hostname, sizeof(hostname)-1))
1225 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1226 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1227 fdprint(con->fd, tmp);
1229 fds[0].fd = con->fd;
1230 fds[0].events = POLLIN;
1232 fds[1].fd = con->p[0];
1233 fds[1].events = POLLIN;
1236 res = ast_poll(fds, 2, -1);
1239 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1242 if (fds[0].revents) {
1243 res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
1248 if (strncmp(tmp, "cli quit after ", 15) == 0) {
1249 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
1252 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
1254 if (fds[1].revents) {
1255 res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
1257 ast_log(LOG_ERROR, "read returned %d\n", res);
1260 res = write(con->fd, tmp, res);
1265 if (!ast_opt_hide_connect) {
1266 ast_verb(3, "Remote UNIX connection disconnected\n");
1276 static void *listener(void *unused)
1278 struct sockaddr_un sunaddr;
1283 struct pollfd fds[1];
1287 fds[0].fd = ast_socket;
1288 fds[0].events = POLLIN;
1289 s = ast_poll(fds, 1, -1);
1290 pthread_testcancel();
1293 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1296 len = sizeof(sunaddr);
1297 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1300 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1302 #if !defined(SO_PASSCRED)
1306 /* turn on socket credentials passing. */
1307 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1308 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1311 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1312 if (consoles[x].fd >= 0) {
1315 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1316 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1317 consoles[x].fd = -1;
1318 fdprint(s, "Server failed to create pipe\n");
1322 flags = fcntl(consoles[x].p[1], F_GETFL);
1323 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1325 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1326 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1327 to know if the user didn't send the credentials. */
1328 consoles[x].uid = -2;
1329 consoles[x].gid = -2;
1330 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1331 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1332 close(consoles[x].p[0]);
1333 close(consoles[x].p[1]);
1334 consoles[x].fd = -1;
1335 fdprint(s, "Server failed to spawn thread\n");
1340 if (x >= AST_MAX_CONNECTS) {
1341 fdprint(s, "No more connections allowed\n");
1342 ast_log(LOG_WARNING, "No more connections allowed\n");
1344 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1345 ast_verb(3, "Remote UNIX connection\n");
1353 static int ast_makesocket(void)
1355 struct sockaddr_un sunaddr;
1361 for (x = 0; x < AST_MAX_CONNECTS; x++)
1362 consoles[x].fd = -1;
1363 unlink(ast_config_AST_SOCKET);
1364 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1365 if (ast_socket < 0) {
1366 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1369 memset(&sunaddr, 0, sizeof(sunaddr));
1370 sunaddr.sun_family = AF_LOCAL;
1371 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1372 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1374 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1379 res = listen(ast_socket, 2);
1381 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1386 if (ast_register_verbose(network_verboser)) {
1387 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1390 ast_pthread_create_background(<hread, NULL, listener, NULL);
1392 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1394 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1395 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1400 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1402 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1403 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1408 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1409 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1411 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1414 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1416 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1417 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1423 static int ast_tryconnect(void)
1425 struct sockaddr_un sunaddr;
1427 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1428 if (ast_consock < 0) {
1429 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1432 memset(&sunaddr, 0, sizeof(sunaddr));
1433 sunaddr.sun_family = AF_LOCAL;
1434 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1435 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1444 /*! \brief Urgent handler
1446 Called by soft_hangup to interrupt the poll, read, or other
1447 system call. We don't actually need to do anything though.
1448 Remember: Cannot EVER ast_log from within a signal handler
1450 static void _urg_handler(int num)
1455 static struct sigaction urg_handler = {
1456 .sa_handler = _urg_handler,
1459 static void _hup_handler(int num)
1462 if (option_verbose > 1)
1463 printf("Received HUP signal -- Reloading configs\n");
1465 execvp(_argv[0], _argv);
1466 sig_flags.need_reload = 1;
1467 if (sig_alert_pipe[1] != -1) {
1468 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1469 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1474 static struct sigaction hup_handler = {
1475 .sa_handler = _hup_handler,
1478 static void _child_handler(int sig)
1480 /* Must not ever ast_log or ast_verbose within signal handler */
1484 * Reap all dead children -- not just one
1486 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1488 if (n == 0 && option_debug)
1489 printf("Huh? Child handler, but nobody there?\n");
1492 static struct sigaction child_handler = {
1493 .sa_handler = _child_handler,
1496 /*! \brief Set maximum open files */
1497 static void set_ulimit(int value)
1499 struct rlimit l = {0, 0};
1502 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1509 if (setrlimit(RLIMIT_NOFILE, &l)) {
1510 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1514 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1519 /*! \brief Set an X-term or screen title */
1520 static void set_title(char *text)
1522 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1523 fprintf(stdout, "\033]2;%s\007", text);
1526 static void set_icon(char *text)
1528 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1529 fprintf(stdout, "\033]1;%s\007", text);
1532 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1533 else. If your PBX has heavy activity on it, this is a good thing. */
1534 int ast_set_priority(int pri)
1536 struct sched_param sched;
1537 memset(&sched, 0, sizeof(sched));
1540 sched.sched_priority = 10;
1541 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1542 ast_log(LOG_WARNING, "Unable to set high priority\n");
1546 ast_verbose("Set to realtime thread\n");
1548 sched.sched_priority = 0;
1549 /* According to the manpage, these parameters can never fail. */
1550 sched_setscheduler(0, SCHED_OTHER, &sched);
1554 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1555 ast_log(LOG_WARNING, "Unable to set high priority\n");
1559 ast_verbose("Set to high priority\n");
1561 /* According to the manpage, these parameters can never fail. */
1562 setpriority(PRIO_PROCESS, 0, 0);
1568 static void ast_run_atexits(void)
1570 struct ast_atexit *ae;
1571 AST_RWLIST_RDLOCK(&atexits);
1572 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1576 AST_RWLIST_UNLOCK(&atexits);
1579 static void quit_handler(int num, int niceness, int safeshutdown, int restart)
1581 char filename[80] = "";
1584 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1585 ast_cdr_engine_term();
1589 /* Begin shutdown routine, hanging up active channels */
1590 ast_begin_shutdown(1);
1591 if (option_verbose && ast_opt_console)
1592 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1596 /* Wait up to 15 seconds for all channels to go away */
1599 if (!ast_active_channels())
1603 /* Sleep 1/10 of a second */
1608 ast_begin_shutdown(0);
1609 if (option_verbose && ast_opt_console)
1610 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1612 if (!ast_active_channels())
1620 if (!shuttingdown) {
1621 if (option_verbose && ast_opt_console)
1622 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1627 ast_module_shutdown();
1629 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1631 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1632 if (!ast_strlen_zero(filename))
1633 ast_el_write_history(filename);
1636 if (el_hist != NULL)
1637 history_end(el_hist);
1640 ast_verbose("Executing last minute cleanups\n");
1642 /* Called on exit */
1643 if (option_verbose && ast_opt_console)
1644 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1645 ast_debug(1, "Asterisk ending (%d).\n", num);
1646 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1647 if (ast_socket > -1) {
1648 pthread_cancel(lthread);
1651 unlink(ast_config_AST_SOCKET);
1653 if (ast_consock > -1)
1655 if (!ast_opt_remote)
1656 unlink(ast_config_AST_PID);
1657 printf("%s", term_quit());
1659 if (option_verbose || ast_opt_console)
1660 ast_verbose("Preparing for Asterisk restart...\n");
1661 /* Mark all FD's for closing on exec */
1662 for (x=3; x < 32768; x++) {
1663 fcntl(x, F_SETFD, FD_CLOEXEC);
1665 if (option_verbose || ast_opt_console)
1666 ast_verbose("Asterisk is now restarting...\n");
1672 /* If there is a consolethread running send it a SIGHUP
1673 so it can execvp, otherwise we can do it ourselves */
1674 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1675 pthread_kill(consolethread, SIGHUP);
1676 /* Give the signal handler some time to complete */
1679 execvp(_argv[0], _argv);
1688 static void __quit_handler(int num)
1691 sig_flags.need_quit = 1;
1692 if (sig_alert_pipe[1] != -1) {
1693 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1694 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1697 /* There is no need to restore the signal handler here, since the app
1698 * is going to exit */
1701 static void __remote_quit_handler(int num)
1703 sig_flags.need_quit = 1;
1706 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1710 /* Check for verboser preamble */
1715 if (!strncmp(s, cmp, strlen(cmp))) {
1716 c = s + strlen(cmp);
1717 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1723 static void console_verboser(const char *s)
1726 const char *c = NULL;
1728 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1729 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1730 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1731 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1743 /* Wake up a poll()ing console */
1744 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1745 pthread_kill(consolethread, SIGURG);
1748 static int ast_all_zeros(char *s)
1758 static void consolehandler(char *s)
1760 printf("%s", term_end());
1763 /* Called when readline data is available */
1764 if (!ast_all_zeros(s))
1765 ast_el_add_history(s);
1766 /* The real handler for bang */
1769 ast_safe_system(s+1);
1771 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1773 ast_cli_command(STDOUT_FILENO, s);
1776 static int remoteconsolehandler(char *s)
1780 /* Called when readline data is available */
1781 if (!ast_all_zeros(s))
1782 ast_el_add_history(s);
1783 /* The real handler for bang */
1786 ast_safe_system(s+1);
1788 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1791 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1792 (s[4] == '\0' || isspace(s[4]))) {
1793 quit_handler(0, 0, 0, 0);
1800 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1804 e->command = "core show version";
1806 "Usage: core show version\n"
1807 " Shows Asterisk version information.\n";
1814 return CLI_SHOWUSAGE;
1815 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1816 ast_get_version(), ast_build_user, ast_build_hostname,
1817 ast_build_machine, ast_build_os, ast_build_date);
1822 static int handle_quit(int fd, int argc, char *argv[])
1825 return RESULT_SHOWUSAGE;
1826 quit_handler(0, 0, 1, 0);
1827 return RESULT_SUCCESS;
1831 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1835 e->command = "core stop now";
1837 "Usage: core stop now\n"
1838 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1844 if (a->argc != e->args)
1845 return CLI_SHOWUSAGE;
1846 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1850 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1854 e->command = "core stop gracefully";
1856 "Usage: core stop gracefully\n"
1857 " Causes Asterisk to not accept new calls, and exit when all\n"
1858 " active calls have terminated normally.\n";
1864 if (a->argc != e->args)
1865 return CLI_SHOWUSAGE;
1866 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1870 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1874 e->command = "core stop when convenient";
1876 "Usage: core stop when convenient\n"
1877 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1883 if (a->argc != e->args)
1884 return CLI_SHOWUSAGE;
1885 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
1886 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1890 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1894 e->command = "core restart now";
1896 "Usage: core restart now\n"
1897 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1904 if (a->argc != e->args)
1905 return CLI_SHOWUSAGE;
1906 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1910 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1914 e->command = "core restart gracefully";
1916 "Usage: core restart gracefully\n"
1917 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1918 " restart when all active calls have ended.\n";
1924 if (a->argc != e->args)
1925 return CLI_SHOWUSAGE;
1926 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1930 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1934 e->command = "core restart when convenient";
1936 "Usage: core restart when convenient\n"
1937 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1943 if (a->argc != e->args)
1944 return CLI_SHOWUSAGE;
1945 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
1946 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1950 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1954 e->command = "core abort shutdown";
1956 "Usage: core abort shutdown\n"
1957 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1958 " call operations.\n";
1964 if (a->argc != e->args)
1965 return CLI_SHOWUSAGE;
1966 ast_cancel_shutdown();
1971 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1977 "Usage: !<command>\n"
1978 " Executes a given shell command\n";
1986 static const char warranty_lines[] = {
1990 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
1991 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
1992 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
1993 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
1994 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
1995 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
1996 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
1997 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
1998 "REPAIR OR CORRECTION.\n"
2000 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2001 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2002 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2003 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2004 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2005 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2006 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2007 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2008 "POSSIBILITY OF SUCH DAMAGES.\n"
2011 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2015 e->command = "core show warranty";
2017 "Usage: core show warranty\n"
2018 " Shows the warranty (if any) for this copy of Asterisk.\n";
2024 ast_cli(a->fd, "%s", warranty_lines);
2029 static const char license_lines[] = {
2031 "This program is free software; you can redistribute it and/or modify\n"
2032 "it under the terms of the GNU General Public License version 2 as\n"
2033 "published by the Free Software Foundation.\n"
2035 "This program also contains components licensed under other licenses.\n"
2038 "This program is distributed in the hope that it will be useful,\n"
2039 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2040 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2041 "GNU General Public License for more details.\n"
2043 "You should have received a copy of the GNU General Public License\n"
2044 "along with this program; if not, write to the Free Software\n"
2045 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2048 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2052 e->command = "core show license";
2054 "Usage: core show license\n"
2055 " Shows the license(s) for this copy of Asterisk.\n";
2061 ast_cli(a->fd, "%s", license_lines);
2066 #define ASTERISK_PROMPT "*CLI> "
2068 #define ASTERISK_PROMPT2 "%s*CLI> "
2070 static struct ast_cli_entry cli_asterisk[] = {
2071 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2072 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2073 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2074 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2075 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2076 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2077 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2078 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2079 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2080 AST_CLI_DEFINE(handle_version, "Display version info"),
2081 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2082 #if !defined(LOW_MEMORY)
2083 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2084 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2085 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2086 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2088 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2089 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2090 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2091 #endif /* ! LOW_MEMORY */
2094 static int ast_el_read_char(EditLine *editline, char *cp)
2098 struct pollfd fds[2];
2101 #define EL_BUF_SIZE 512
2102 char buf[EL_BUF_SIZE];
2106 fds[0].fd = ast_consock;
2107 fds[0].events = POLLIN;
2108 if (!ast_opt_exec) {
2109 fds[1].fd = STDIN_FILENO;
2110 fds[1].events = POLLIN;
2113 res = ast_poll(fds, max, -1);
2115 if (sig_flags.need_quit)
2119 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2123 if (!ast_opt_exec && fds[1].revents) {
2124 num_read = read(STDIN_FILENO, cp, 1);
2130 if (fds[0].revents) {
2132 res = read(ast_consock, buf, sizeof(buf) - 1);
2133 /* if the remote side disappears exit */
2135 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2136 if (!ast_opt_reconnect) {
2137 quit_handler(0, 0, 0, 0);
2140 int reconnects_per_second = 20;
2141 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2142 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2143 if (ast_tryconnect()) {
2144 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2145 printf("%s", term_quit());
2148 fdsend(ast_consock, "logger mute silent");
2150 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2153 usleep(1000000 / reconnects_per_second);
2155 if (tries >= 30 * reconnects_per_second) {
2156 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2157 quit_handler(0, 0, 0, 0);
2164 /* Strip preamble from asynchronous events, too */
2165 for (tmp = buf; *tmp; tmp++) {
2167 memmove(tmp, tmp + 1, strlen(tmp));
2173 /* Write over the CLI prompt */
2174 if (!ast_opt_exec && !lastpos) {
2175 if (write(STDOUT_FILENO, "\r", 1) < 0) {
2178 if (write(STDOUT_FILENO, buf, res) < 0) {
2180 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2192 static struct ast_str *prompt = NULL;
2194 static char *cli_prompt(EditLine *editline)
2199 static int cli_prompt_changes = 0;
2204 if (prompt == NULL) {
2205 prompt = ast_str_create(100);
2206 } else if (!cli_prompt_changes) {
2207 return ast_str_buffer(prompt);
2209 ast_str_reset(prompt);
2212 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2214 struct timeval ts = ast_tvnow();
2215 while (*t != '\0') {
2217 char hostname[MAXHOSTNAMELEN] = "";
2219 struct ast_tm tm = { 0, };
2220 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2224 case 'C': /* color */
2226 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2227 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2229 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2230 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2234 /* If the color has been reset correctly, then there's no need to reset it later */
2235 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2237 case 'd': /* date */
2238 if (ast_localtime(&ts, &tm, NULL)) {
2239 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2240 ast_str_append(&prompt, 0, "%s", tmp);
2241 cli_prompt_changes++;
2244 case 'g': /* group */
2245 if ((gr = getgrgid(getgid()))) {
2246 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2249 case 'h': /* hostname */
2250 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2251 ast_str_append(&prompt, 0, "%s", hostname);
2253 ast_str_append(&prompt, 0, "%s", "localhost");
2256 case 'H': /* short hostname */
2257 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2259 if ((dotptr = strchr(hostname, '.'))) {
2262 ast_str_append(&prompt, 0, "%s", hostname);
2264 ast_str_append(&prompt, 0, "%s", "localhost");
2267 #ifdef HAVE_GETLOADAVG
2268 case 'l': /* load avg */
2270 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2272 getloadavg(list, 3);
2273 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2274 cli_prompt_changes++;
2278 case 's': /* Asterisk system name (from asterisk.conf) */
2279 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2281 case 't': /* time */
2282 if (ast_localtime(&ts, &tm, NULL)) {
2283 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2284 ast_str_append(&prompt, 0, "%s", tmp);
2285 cli_prompt_changes++;
2288 case 'u': /* username */
2289 if ((pw = getpwuid(getuid()))) {
2290 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2293 case '#': /* process console or remote? */
2294 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2296 case '%': /* literal % */
2297 ast_str_append(&prompt, 0, "%c", '%');
2299 case '\0': /* % is last character - prevent bug */
2304 ast_str_append(&prompt, 0, "%c", *t);
2309 /* Force colors back to normal at end */
2310 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2312 } else if (remotehostname) {
2313 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2315 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2318 return ast_str_buffer(prompt);
2321 static char **ast_el_strtoarr(char *buf)
2323 char **match_list = NULL, **match_list_tmp, *retstr;
2324 size_t match_list_len;
2328 while ( (retstr = strsep(&buf, " ")) != NULL) {
2330 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2332 if (matches + 1 >= match_list_len) {
2333 match_list_len <<= 1;
2334 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2335 match_list = match_list_tmp;
2338 ast_free(match_list);
2339 return (char **) NULL;
2343 match_list[matches++] = ast_strdup(retstr);
2347 return (char **) NULL;
2349 if (matches >= match_list_len) {
2350 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2351 match_list = match_list_tmp;
2354 ast_free(match_list);
2355 return (char **) NULL;
2359 match_list[matches] = (char *) NULL;
2364 static int ast_el_sort_compare(const void *i1, const void *i2)
2368 s1 = ((char **)i1)[0];
2369 s2 = ((char **)i2)[0];
2371 return strcasecmp(s1, s2);
2374 static int ast_cli_display_match_list(char **matches, int len, int max)
2376 int i, idx, limit, count;
2377 int screenwidth = 0;
2378 int numoutput = 0, numoutputline = 0;
2380 screenwidth = ast_get_termcols(STDOUT_FILENO);
2382 /* find out how many entries can be put on one line, with two spaces between strings */
2383 limit = screenwidth / (max + 2);
2387 /* how many lines of output */
2388 count = len / limit;
2389 if (count * limit < len)
2394 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2396 for (; count > 0; count--) {
2398 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2400 /* Don't print dupes */
2401 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2403 ast_free(matches[idx]);
2404 matches[idx] = NULL;
2410 fprintf(stdout, "%-*s ", max, matches[idx]);
2411 ast_free(matches[idx]);
2412 matches[idx] = NULL;
2414 if (numoutputline > 0)
2415 fprintf(stdout, "\n");
2422 static char *cli_complete(EditLine *editline, int ch)
2428 int retval = CC_ERROR;
2429 char buf[2048], savechr;
2432 LineInfo *lf = (LineInfo *)el_line(editline);
2434 savechr = *(char *)lf->cursor;
2435 *(char *)lf->cursor = '\0';
2436 ptr = (char *)lf->cursor;
2438 while (ptr > lf->buffer) {
2439 if (isspace(*ptr)) {
2447 len = lf->cursor - ptr;
2449 if (ast_opt_remote) {
2450 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2451 fdsend(ast_consock, buf);
2452 res = read(ast_consock, buf, sizeof(buf) - 1);
2454 nummatches = atoi(buf);
2456 if (nummatches > 0) {
2458 int mlen = 0, maxmbuf = 2048;
2459 /* Start with a 2048 byte buffer */
2460 if (!(mbuf = ast_malloc(maxmbuf))) {
2461 lf->cursor[0] = savechr;
2462 return (char *)(CC_ERROR);
2464 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2465 fdsend(ast_consock, buf);
2468 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2469 if (mlen + 1024 > maxmbuf) {
2470 /* Every step increment buffer 1024 bytes */
2472 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2473 lf->cursor[0] = savechr;
2474 return (char *)(CC_ERROR);
2477 /* Only read 1024 bytes at a time */
2478 res = read(ast_consock, mbuf + mlen, 1024);
2484 matches = ast_el_strtoarr(mbuf);
2487 matches = (char **) NULL;
2489 char **p, *oldbuf=NULL;
2491 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2492 for (p = matches; p && *p; p++) {
2493 if (!oldbuf || strcmp(*p,oldbuf))
2501 int matches_num, maxlen, match_len;
2503 if (matches[0][0] != '\0') {
2504 el_deletestr(editline, (int) len);
2505 el_insertstr(editline, matches[0]);
2506 retval = CC_REFRESH;
2509 if (nummatches == 1) {
2510 /* Found an exact match */
2511 el_insertstr(editline, " ");
2512 retval = CC_REFRESH;
2514 /* Must be more than one match */
2515 for (i = 1, maxlen = 0; matches[i]; i++) {
2516 match_len = strlen(matches[i]);
2517 if (match_len > maxlen)
2520 matches_num = i - 1;
2521 if (matches_num >1) {
2522 fprintf(stdout, "\n");
2523 ast_cli_display_match_list(matches, nummatches, maxlen);
2524 retval = CC_REDISPLAY;
2526 el_insertstr(editline," ");
2527 retval = CC_REFRESH;
2530 for (i = 0; matches[i]; i++)
2531 ast_free(matches[i]);
2535 lf->cursor[0] = savechr;
2537 return (char *)(long)retval;
2540 static int ast_el_initialize(void)
2543 char *editor = getenv("AST_EDITOR");
2547 if (el_hist != NULL)
2548 history_end(el_hist);
2550 el = el_init("asterisk", stdin, stdout, stderr);
2551 el_set(el, EL_PROMPT, cli_prompt);
2553 el_set(el, EL_EDITMODE, 1);
2554 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2555 el_hist = history_init();
2556 if (!el || !el_hist)
2559 /* setup history with 100 entries */
2560 history(el_hist, &ev, H_SETSIZE, 100);
2562 el_set(el, EL_HIST, history, el_hist);
2564 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2565 /* Bind <tab> to command completion */
2566 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2567 /* Bind ? to command completion */
2568 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2569 /* Bind ^D to redisplay */
2570 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2575 #define MAX_HISTORY_COMMAND_LENGTH 256
2577 static int ast_el_add_history(char *buf)
2581 if (el_hist == NULL || el == NULL)
2582 ast_el_initialize();
2583 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2585 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2588 static int ast_el_write_history(char *filename)
2592 if (el_hist == NULL || el == NULL)
2593 ast_el_initialize();
2595 return (history(el_hist, &ev, H_SAVE, filename));
2598 static int ast_el_read_history(char *filename)
2600 char buf[MAX_HISTORY_COMMAND_LENGTH];
2604 if (el_hist == NULL || el == NULL)
2605 ast_el_initialize();
2607 if ((f = fopen(filename, "r")) == NULL)
2611 if (!fgets(buf, sizeof(buf), f))
2613 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2615 if (ast_all_zeros(buf))
2617 if ((ret = ast_el_add_history(buf)) == -1)
2625 static void ast_remotecontrol(char *data)
2629 char filename[80] = "";
2634 char *stringp = NULL;
2639 memset(&sig_flags, 0, sizeof(sig_flags));
2640 signal(SIGINT, __remote_quit_handler);
2641 signal(SIGTERM, __remote_quit_handler);
2642 signal(SIGHUP, __remote_quit_handler);
2644 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2645 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2649 char prefix[] = "cli quit after ";
2650 char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
2651 sprintf(tmp, "%s%s", prefix, data);
2652 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2653 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2654 if (sig_flags.need_quit == 1) {
2660 hostname = strsep(&stringp, "/");
2661 cpid = strsep(&stringp, "/");
2662 version = strsep(&stringp, "\n");
2664 version = "<Version Unknown>";
2666 strsep(&stringp, ".");
2673 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2674 fdsend(ast_consock, tmp);
2675 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2676 fdsend(ast_consock, tmp);
2678 fdsend(ast_consock, "logger mute silent");
2680 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2683 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2685 fds.fd = ast_consock;
2686 fds.events = POLLIN;
2688 while (ast_poll(&fds, 1, 60000) > 0) {
2689 char buffer[512] = "", *curline = buffer, *nextline;
2690 int not_written = 1;
2692 if (sig_flags.need_quit == 1) {
2696 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
2701 if ((nextline = strchr(curline, '\n'))) {
2704 nextline = strchr(curline, '\0');
2707 /* Skip verbose lines */
2708 if (*curline != 127) {
2710 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2711 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
2715 } while (!ast_strlen_zero(curline));
2717 /* No non-verbose output in 60 seconds. */
2725 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2726 remotehostname = hostname;
2728 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2729 if (el_hist == NULL || el == NULL)
2730 ast_el_initialize();
2732 el_set(el, EL_GETCFN, ast_el_read_char);
2734 if (!ast_strlen_zero(filename))
2735 ast_el_read_history(filename);
2738 ebuf = (char *)el_gets(el, &num);
2740 if (sig_flags.need_quit == 1) {
2744 if (!ebuf && write(1, "", 1) < 0)
2747 if (!ast_strlen_zero(ebuf)) {
2748 if (ebuf[strlen(ebuf)-1] == '\n')
2749 ebuf[strlen(ebuf)-1] = '\0';
2750 if (!remoteconsolehandler(ebuf)) {
2751 /* Strip preamble from output */
2753 for (temp = ebuf; *temp; temp++) {
2755 memmove(temp, temp + 1, strlen(temp));
2759 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2761 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2767 printf("\nDisconnected from Asterisk server\n");
2770 static int show_version(void)
2772 printf("Asterisk %s\n", ast_get_version());
2776 static int show_cli_help(void) {
2777 printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
2778 printf("Usage: asterisk [OPTIONS]\n");
2779 printf("Valid Options:\n");
2780 printf(" -V Display version number and exit\n");
2781 printf(" -C <configfile> Use an alternate configuration file\n");
2782 printf(" -G <group> Run as a group other than the caller\n");
2783 printf(" -U <user> Run as a user other than the caller\n");
2784 printf(" -c Provide console CLI\n");
2785 printf(" -d Enable extra debugging\n");
2786 #if HAVE_WORKING_FORK
2787 printf(" -f Do not fork\n");
2788 printf(" -F Always fork\n");
2790 printf(" -g Dump core in case of a crash\n");
2791 printf(" -h This help screen\n");
2792 printf(" -i Initialize crypto keys at startup\n");
2793 printf(" -I Enable internal timing if DAHDI timer is available\n");
2794 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2795 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2796 printf(" -m Mute debugging and console output on the console\n");
2797 printf(" -n Disable console colorization\n");
2798 printf(" -p Run as pseudo-realtime thread\n");
2799 printf(" -q Quiet mode (suppress output)\n");
2800 printf(" -r Connect to Asterisk on this machine\n");
2801 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2802 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
2803 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2804 printf(" belong after they are done\n");
2805 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2806 printf(" of output to the CLI\n");
2807 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2808 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2809 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
2810 printf(" -W Adjust terminal colors to compensate for a light background\n");
2815 static void ast_readconfig(void)
2817 struct ast_config *cfg;
2818 struct ast_variable *v;
2819 char *config = DEFAULT_CONFIG_FILE;
2820 char hostname[MAXHOSTNAMELEN] = "";
2821 struct ast_flags config_flags = { 0 };
2823 unsigned int dbdir:1;
2824 unsigned int keydir:1;
2827 if (ast_opt_override_config) {
2828 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
2829 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
2830 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2832 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
2834 /* init with buildtime config */
2835 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2836 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2837 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2838 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
2839 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2840 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2841 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2842 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2843 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2844 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2845 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2846 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2847 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2849 ast_set_default_eid(&ast_eid_default);
2851 /* no asterisk.conf? no problem, use buildtime config! */
2852 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
2856 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2857 if (!strcasecmp(v->name, "astctlpermissions"))
2858 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2859 else if (!strcasecmp(v->name, "astctlowner"))
2860 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2861 else if (!strcasecmp(v->name, "astctlgroup"))
2862 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2863 else if (!strcasecmp(v->name, "astctl"))
2864 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2867 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2868 if (!strcasecmp(v->name, "astetcdir")) {
2869 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2870 } else if (!strcasecmp(v->name, "astspooldir")) {
2871 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2872 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
2873 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2874 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2876 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2877 } else if (!strcasecmp(v->name, "astdbdir")) {
2878 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2880 } else if (!strcasecmp(v->name, "astdatadir")) {
2881 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2883 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2884 } else if (!strcasecmp(v->name, "astkeydir")) {
2885 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2887 } else if (!strcasecmp(v->name, "astlogdir")) {
2888 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2889 } else if (!strcasecmp(v->name, "astagidir")) {
2890 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2891 } else if (!strcasecmp(v->name, "astrundir")) {
2892 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2893 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2894 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2895 } else if (!strcasecmp(v->name, "astmoddir")) {
2896 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2900 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2901 /* verbose level (-v at startup) */
2902 if (!strcasecmp(v->name, "verbose")) {
2903 option_verbose = atoi(v->value);
2904 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2905 } else if (!strcasecmp(v->name, "timestamp")) {
2906 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2907 /* whether or not to support #exec in config files */
2908 } else if (!strcasecmp(v->name, "execincludes")) {
2909 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2910 /* debug level (-d at startup) */
2911 } else if (!strcasecmp(v->name, "debug")) {
2913 if (sscanf(v->value, "%30d", &option_debug) != 1) {
2914 option_debug = ast_true(v->value);
2916 #if HAVE_WORKING_FORK
2917 /* Disable forking (-f at startup) */
2918 } else if (!strcasecmp(v->name, "nofork")) {
2919 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2920 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2921 } else if (!strcasecmp(v->name, "alwaysfork")) {
2922 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2924 /* Run quietly (-q at startup ) */
2925 } else if (!strcasecmp(v->name, "quiet")) {
2926 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2927 /* Run as console (-c at startup, implies nofork) */
2928 } else if (!strcasecmp(v->name, "console")) {
2929 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2930 /* Run with high priority if the O/S permits (-p at startup) */
2931 } else if (!strcasecmp(v->name, "highpriority")) {
2932 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2933 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2934 } else if (!strcasecmp(v->name, "initcrypto")) {
2935 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2936 /* Disable ANSI colors for console (-c at startup) */
2937 } else if (!strcasecmp(v->name, "nocolor")) {
2938 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2939 /* Disable some usage warnings for picky people :p */
2940 } else if (!strcasecmp(v->name, "dontwarn")) {
2941 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2942 /* Dump core in case of crash (-g) */
2943 } else if (!strcasecmp(v->name, "dumpcore")) {
2944 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2945 /* Cache recorded sound files to another directory during recording */
2946 } else if (!strcasecmp(v->name, "cache_record_files")) {
2947 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2948 /* Specify cache directory */
2949 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2950 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2951 /* Build transcode paths via SLINEAR, instead of directly */
2952 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2953 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2954 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2955 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2956 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2957 /* Enable internal timing */
2958 } else if (!strcasecmp(v->name, "internal_timing")) {
2959 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2960 } else if (!strcasecmp(v->name, "maxcalls")) {
2961 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2962 option_maxcalls = 0;
2964 } else if (!strcasecmp(v->name, "maxload")) {
2967 if (getloadavg(test, 1) == -1) {
2968 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2969 option_maxload = 0.0;
2970 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2971 option_maxload = 0.0;
2973 /* Set the maximum amount of open files */
2974 } else if (!strcasecmp(v->name, "maxfiles")) {
2975 option_maxfiles = atoi(v->value);
2976 set_ulimit(option_maxfiles);
2977 /* What user to run as */
2978 } else if (!strcasecmp(v->name, "runuser")) {
2979 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
2980 /* What group to run as */
2981 } else if (!strcasecmp(v->name, "rungroup")) {
2982 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
2983 } else if (!strcasecmp(v->name, "systemname")) {
2984 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
2985 } else if (!strcasecmp(v->name, "autosystemname")) {
2986 if (ast_true(v->value)) {
2987 if (!gethostname(hostname, sizeof(hostname) - 1))
2988 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
2990 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2991 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
2993 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2996 } else if (!strcasecmp(v->name, "languageprefix")) {
2997 ast_language_is_prefix = ast_true(v->value);
2998 } else if (!strcasecmp(v->name, "lockmode")) {
2999 if (!strcasecmp(v->value, "lockfile")) {
3000 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3001 } else if (!strcasecmp(v->value, "flock")) {
3002 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3004 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3005 "defaulting to 'lockfile'\n", v->value);
3006 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3008 #if defined(HAVE_SYSINFO)
3009 } else if (!strcasecmp(v->name, "minmemfree")) {
3010 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
3011 * if the amount of free memory falls below this watermark */
3012 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3013 option_minmemfree = 0;
3016 } else if (!strcasecmp(v->name, "entityid")) {
3017 struct ast_eid tmp_eid;
3018 if (!ast_str_to_eid(&tmp_eid, v->value)) {
3019 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3020 ast_eid_default = tmp_eid;
3022 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3023 } else if (!strcasecmp(v->name, "lightbackground")) {
3024 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3025 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3026 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3027 } else if (!strcasecmp(v->name, "hideconnect")) {
3028 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3029 } else if (!strcasecmp(v->name, "lockconfdir")) {
3030 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3033 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3035 if (sscanf(v->value, "%30f", &version) != 1) {
3036 ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3039 if (!strcasecmp(v->name, "app_set")) {
3040 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3041 } else if (!strcasecmp(v->name, "res_agi")) {
3042 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3043 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3044 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3047 ast_config_destroy(cfg);
3050 static void *monitor_sig_flags(void *unused)
3053 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3055 ast_poll(&p, 1, -1);
3056 if (sig_flags.need_reload) {
3057 sig_flags.need_reload = 0;
3058 ast_module_reload(NULL);
3060 if (sig_flags.need_quit) {
3061 sig_flags.need_quit = 0;
3062 quit_handler(0, 0, 1, 0);
3064 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3071 static void *canary_thread(void *unused)
3073 struct stat canary_stat;
3076 /* Give the canary time to sing */
3080 stat(canary_filename, &canary_stat);
3082 if (now.tv_sec > canary_stat.st_mtime + 60) {
3083 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");
3084 ast_set_priority(0);
3088 /* Check the canary once a minute */
3093 /* Used by libc's atexit(3) function */
3094 static void canary_exit(void)
3097 kill(canary_pid, SIGKILL);
3100 static void run_startup_commands(void)
3103 struct ast_config *cfg;
3104 struct ast_flags cfg_flags = { 0 };
3105 struct ast_variable *v;
3107 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3109 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3113 fd = open("/dev/null", O_RDWR);
3115 ast_config_destroy(cfg);
3119 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3120 if (ast_true(v->value))
3121 ast_cli_command(fd, v->name);
3125 ast_config_destroy(cfg);
3128 int main(int argc, char *argv[])
3131 char filename[80] = "";
3132 char hostname[MAXHOSTNAMELEN] = "";
3141 const char *runuser = NULL, *rungroup = NULL;
3142 char *remotesock = NULL;
3143 int moduleresult; /*!< Result from the module load subsystem */
3145 /* Remember original args for restart */
3146 if (argc > ARRAY_LEN(_argv) - 1) {
3147 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
3148 argc = ARRAY_LEN(_argv) - 1;
3150 for (x = 0; x < argc; x++)
3157 /* if the progname is rasterisk consider it a remote console */
3158 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
3159 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3161 if (gethostname(hostname, sizeof(hostname)-1))
3162 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
3163 ast_mainpid = getpid();
3167 ast_builtins_init();
3174 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3175 /* Check for options */
3176 while ((c = getopt(argc, argv, "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:")) != -1) {
3177 /*!\note Please keep the ordering here to alphabetical, capital letters
3178 * first. This will make it easier in the future to select unused
3179 * option flags for new features. */
3181 case 'B': /* Force black background */
3182 ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3183 ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
3186 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES);
3189 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
3190 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
3193 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3197 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3199 #if defined(HAVE_SYSINFO)
3201 if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3202 option_minmemfree = 0;
3206 #if HAVE_WORKING_FORK
3208 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
3211 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3215 rungroup = ast_strdupa(optarg);
3218 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
3224 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
3227 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
3230 if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3231 option_maxload = 0.0;
3235 if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3236 option_maxcalls = 0;
3240 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
3243 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
3246 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
3249 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
3252 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
3255 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3258 remotesock = ast_strdupa(optarg);
3261 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
3264 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
3267 runuser = ast_strdupa(optarg);
3274 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3276 case 'W': /* White background */
3277 ast_set_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
3278 ast_clear_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3281 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
3282 xarg = ast_strdupa(optarg);
3289 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
3290 if (ast_register_verbose(console_verboser)) {
3291 ast_log(LOG_WARNING, "Unable to register console verboser?\n");
3296 if (ast_opt_console && !option_verbose)
3297 ast_verbose("[ Booting...\n");
3299 /* For remote connections, change the name of the remote connection.
3300 * We do this for the benefit of init scripts (which need to know if/when
3301 * the main asterisk process has died yet). */
3302 if (ast_opt_remote) {
3303 strcpy(argv[0], "rasterisk");
3304 for (x = 1; x < argc; x++) {
3305 argv[x] = argv[0] + 10;
3309 if (ast_opt_console && !option_verbose) {
3310 ast_verbose("[ Reading Master Configuration ]\n");
3315 if (ast_opt_remote && remotesock != NULL)
3316 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
3318 if (!ast_language_is_prefix && !ast_opt_remote)
3319 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");
3321 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
3322 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
3323 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
3326 if (ast_opt_dump_core) {
3328 memset(&l, 0, sizeof(l));
3329 l.rlim_cur = RLIM_INFINITY;
3330 l.rlim_max = RLIM_INFINITY;
3331 if (setrlimit(RLIMIT_CORE, &l)) {
3332 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
3336 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
3337 rungroup = ast_config_AST_RUN_GROUP;
3338 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
3339 runuser = ast_config_AST_RUN_USER;
3341 /* Must install this signal handler up here to ensure that if the canary
3342 * fails to execute that it doesn't kill the Asterisk process.
3344 sigaction(SIGCHLD, &child_handler, NULL);
3346 /* It's common on some platforms to clear /var/run at boot. Create the
3347 * socket file directory before we drop privileges. */
3348 if (mkdir(ast_config_AST_RUN_DIR, 0755) && errno != EEXIST) {
3349 ast_log(LOG_WARNING, "Unable to create socket file directory. Remote consoles will not be able to connect! (%s)\n", strerror(x));
3355 ast_set_priority(ast_opt_high_priority);
3358 if (isroot && rungroup) {
3360 gr = getgrnam(rungroup);
3362 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
3365 if (chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
3366 ast_log(LOG_WARNING, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
3368 if (setgid(gr->gr_gid)) {
3369 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
3372 if (setgroups(0, NULL)) {
3373 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
3377 ast_verbose("Running as group '%s'\n", rungroup);
3380 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
3383 #endif /* HAVE_CAP */
3385 pw = getpwnam(runuser);
3387 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
3390 if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
3391 ast_log(LOG_WARNING, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
3394 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
3395 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
3398 #endif /* HAVE_CAP */
3399 if (!isroot && pw->pw_uid != geteuid()) {
3400 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
3404 if (setgid(pw->pw_gid)) {
3405 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
3408 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
3409 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
3413 if (setuid(pw->pw_uid)) {
3414 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
3418 ast_verbose("Running as user '%s'\n", runuser);
3423 cap = cap_from_text("cap_net_admin=eip");
3425 if (cap_set_proc(cap))
3426 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
3429 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
3431 #endif /* HAVE_CAP */
3434 #endif /* __CYGWIN__ */
3437 if (geteuid() && ast_opt_dump_core) {
3438 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
3439 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
3445 #if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
3446 #if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
3447 #define eaccess euidaccess
3450 if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
3451 ast_log(LOG_ERROR, "Unable to access the running directory (%s). Changing to '/' for compatibility.\n", strerror(errno));
3452 /* If we cannot access the CWD, then we couldn't dump core anyway,
3453 * so chdir("/") won't break anything. */
3455 /* chdir(/) should never fail, so this ends up being a no-op */
3456 ast_log(LOG_ERROR, "chdir(\"/\") failed?!! %s\n", strerror(errno));
3459 #endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
3460 if (!ast_opt_no_fork && !ast_opt_dump_core) {
3461 /* Backgrounding, but no cores, so chdir won't break anything. */
3463 ast_log(LOG_ERROR, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
3469 printf("%s", term_end());
3472 if (ast_opt_console && !option_verbose)
3473 ast_verbose("[ Initializing Custom Configuration Options ]\n");
3474 /* custom config setup */
3475 register_config_cli();
3478 if (ast_opt_console) {
3479 if (el_hist == NULL || el == NULL)
3480 ast_el_initialize();
3482 if (!ast_strlen_zero(filename))
3483 ast_el_read_history(filename);
3486 if (ast_tryconnect()) {
3487 /* One is already running */
3488 if (ast_opt_remote) {
3490 ast_remotecontrol(xarg);
3491 quit_handler(0, 0, 0, 0);
3494 printf("%s", term_quit());
3495 ast_remotecontrol(NULL);
3496 quit_handler(0, 0, 0, 0);
3499 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
3500 printf("%s", term_quit());
3503 } else if (ast_opt_remote || ast_opt_exec) {
3504 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
3505 printf("%s", term_quit());
3508 /* Blindly write pid file since we couldn't connect */
3509 unlink(ast_config_AST_PID);
3510 f = fopen(ast_config_AST_PID, "w");
3512 fprintf(f, "%ld\n", (long)getpid());
3515 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
3517 #if HAVE_WORKING_FORK
3518 if (ast_opt_always_fork || !ast_opt_no_fork) {
3519 #ifndef HAVE_SBIN_LAUNCHD
3520 if (daemon(1, 0) < 0) {
3521 ast_log(LOG_ERROR, "daemon() failed: %s\n", strerror(errno));
3523 ast_mainpid = getpid();
3524 /* Blindly re-write pid file since we are forking */
3525 unlink(ast_config_AST_PID);
3526 f = fopen(ast_config_AST_PID, "w");
3528 fprintf(f, "%ld\n", (long)ast_mainpid);
3531 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
3533 ast_log(LOG_WARNING, "Mac OS X detected. Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
3538 /* Spawning of astcanary must happen AFTER the call to daemon(3) */
3539 if (isroot && ast_opt_high_priority) {
3540 snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
3542 /* Don't let the canary child kill Asterisk, if it dies immediately */
3543 sigaction(SIGPIPE, &ignore_sig_handler, NULL);
3545 canary_pid = fork();
3546 if (canary_pid == 0) {
3547 char canary_binary[128], *lastslash, ppid[12];
3549 /* Reset signal handler */
3550 signal(SIGCHLD, SIG_DFL);
3551 signal(SIGPIPE, SIG_DFL);
3553 ast_close_fds_above_n(0);
3554 ast_set_priority(0);
3555 snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
3557 execlp("astcanary", "astcanary", canary_filename, ppid, (char *)NULL);
3559 /* If not found, try the same path as used to execute asterisk */
3560 ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
3561 if ((lastslash = strrchr(canary_binary, '/'))) {
3562 ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
3563 execl(canary_binary, "astcanary", canary_filename, (char *)NULL);
3566 /* Should never happen */
3568 } else if (canary_pid > 0) {
3569 pthread_t dont_care;
3570 ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
3573 /* Kill the canary when we exit */
3574 ast_register_atexit(canary_exit);
3577 if (ast_event_init()) {
3578 printf("%s", term_quit());
3582 #ifdef TEST_FRAMEWORK
3583 if (ast_test_init()) {
3584 printf("%s", term_quit());