2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2012, 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 - 2012, Digium, Inc.
43 * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
44 * of <a href="http://www.digium.com">Digium, Inc</a>.
46 * \author Mark Spencer <markster@digium.com>
47 * Also see \ref AstCREDITS
49 * See http://www.asterisk.org for more information about
50 * the Asterisk project. Please do not directly contact
51 * any of the maintainers of this project for assistance;
52 * the project provides a web site, mailing lists, and IRC
53 * channels for your use.
57 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
58 of PBX core functions and CLI interface.
64 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
66 #include "asterisk/_private.h"
68 #undef sched_setscheduler
77 #include <sys/resource.h>
81 #if defined(HAVE_SYSINFO)
82 #include <sys/sysinfo.h>
83 #elif defined(HAVE_SYSCTL)
84 #include <sys/param.h>
85 #include <sys/sysctl.h>
86 #if !defined(__OpenBSD__)
87 #include <sys/vmmeter.h>
88 #if defined(__FreeBSD__)
89 #include <vm/vm_param.h>
92 #if defined(HAVE_SWAPCTL)
99 int daemon(int, int); /* defined in libresolv of all places */
100 #include <sys/loadavg.h>
104 #include <sys/prctl.h>
106 #include <sys/capability.h>
107 #endif /* HAVE_CAP */
110 #include "asterisk/paths.h" /* we define here the variables so better agree on the prototype */
111 #include "asterisk/network.h"
112 #include "asterisk/cli.h"
113 #include "asterisk/channel.h"
114 #include "asterisk/translate.h"
115 #include "asterisk/features.h"
116 #include "asterisk/ulaw.h"
117 #include "asterisk/alaw.h"
118 #include "asterisk/callerid.h"
119 #include "asterisk/image.h"
120 #include "asterisk/tdd.h"
121 #include "asterisk/term.h"
122 #include "asterisk/manager.h"
123 #include "asterisk/cdr.h"
124 #include "asterisk/cel.h"
125 #include "asterisk/pbx.h"
126 #include "asterisk/enum.h"
127 #include "asterisk/http.h"
128 #include "asterisk/udptl.h"
129 #include "asterisk/app.h"
130 #include "asterisk/lock.h"
131 #include "asterisk/utils.h"
132 #include "asterisk/file.h"
133 #include "asterisk/io.h"
134 #include "editline/histedit.h"
135 #include "asterisk/config.h"
136 #include "asterisk/ast_version.h"
137 #include "asterisk/linkedlists.h"
138 #include "asterisk/devicestate.h"
139 #include "asterisk/module.h"
140 #include "asterisk/dsp.h"
141 #include "asterisk/buildinfo.h"
142 #include "asterisk/xmldoc.h"
143 #include "asterisk/poll-compat.h"
144 #include "asterisk/ccss.h"
145 #include "asterisk/test.h"
146 #include "asterisk/rtp_engine.h"
147 #include "asterisk/format.h"
148 #include "asterisk/aoc.h"
150 #include "../defaults.h"
153 #define AF_LOCAL AF_UNIX
154 #define PF_LOCAL PF_UNIX
157 #define AST_MAX_CONNECTS 128
160 /*! \brief Welcome message when starting a CLI interface */
161 #define WELCOME_MESSAGE \
162 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
163 "Created by Mark Spencer <markster@digium.com>\n" \
164 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
165 "This is free software, with components licensed under the GNU General Public\n" \
166 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
167 "certain conditions. Type 'core show license' for details.\n" \
168 "=========================================================================\n", ast_get_version()) \
170 /*! \defgroup main_options Main Configuration Options
171 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
172 * \arg \ref Config_ast "asterisk.conf"
173 * \note Some of them can be changed in the CLI
177 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
178 struct ast_flags ast_compat = { 0 };
180 int option_verbose; /*!< Verbosity level */
181 int option_debug; /*!< Debug level */
182 double option_maxload; /*!< Max load avg on system */
183 int option_maxcalls; /*!< Max number of active calls */
184 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
185 #if defined(HAVE_SYSINFO)
186 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
191 struct ast_eid ast_eid_default;
193 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
194 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
196 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
197 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
200 int fd; /*!< File descriptor */
201 int p[2]; /*!< Pipe */
202 pthread_t t; /*!< Thread of handler */
203 int mute; /*!< Is the console muted for logs */
204 int uid; /*!< Remote user ID. */
205 int gid; /*!< Remote group ID. */
206 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
211 AST_RWLIST_ENTRY(ast_atexit) list;
214 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
216 struct timeval ast_startuptime;
217 struct timeval ast_lastreloadtime;
219 static History *el_hist;
221 static char *remotehostname;
223 struct console consoles[AST_MAX_CONNECTS];
225 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
227 static int ast_el_add_history(char *);
228 static int ast_el_read_history(char *);
229 static int ast_el_write_history(char *);
232 char config_dir[PATH_MAX];
233 char module_dir[PATH_MAX];
234 char spool_dir[PATH_MAX];
235 char monitor_dir[PATH_MAX];
236 char var_dir[PATH_MAX];
237 char data_dir[PATH_MAX];
238 char log_dir[PATH_MAX];
239 char agi_dir[PATH_MAX];
240 char run_dir[PATH_MAX];
241 char key_dir[PATH_MAX];
243 char config_file[PATH_MAX];
244 char db_path[PATH_MAX];
245 char sbin_dir[PATH_MAX];
246 char pid_path[PATH_MAX];
247 char socket_path[PATH_MAX];
248 char run_user[PATH_MAX];
249 char run_group[PATH_MAX];
250 char system_name[128];
253 static struct _cfg_paths cfg_paths;
255 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
256 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
257 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
258 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
259 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
260 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
261 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
262 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
263 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
264 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
265 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
266 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
268 const char *ast_config_AST_DB = cfg_paths.db_path;
269 const char *ast_config_AST_PID = cfg_paths.pid_path;
270 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
271 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
272 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
273 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
275 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
276 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
277 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
278 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
280 extern unsigned int ast_FD_SETSIZE;
282 static char *_argv[256];
284 NOT_SHUTTING_DOWN = -2,
286 /* Valid values for quit_handler niceness below: */
292 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
293 static int restartnow;
294 static pthread_t consolethread = AST_PTHREADT_NULL;
295 static pthread_t mon_sig_flags;
296 static int canary_pid = 0;
297 static char canary_filename[128];
299 static char randompool[256];
301 static int sig_alert_pipe[2] = { -1, -1 };
303 unsigned int need_reload:1;
304 unsigned int need_quit:1;
305 unsigned int need_quit_handler:1;
308 #if !defined(LOW_MEMORY)
309 struct file_version {
310 AST_RWLIST_ENTRY(file_version) list;
315 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
317 void ast_register_file_version(const char *file, const char *version)
319 struct file_version *new;
321 size_t version_length;
323 work = ast_strdupa(version);
324 work = ast_strip(ast_strip_quoted(work, "$", "$"));
325 version_length = strlen(work) + 1;
327 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
331 new->version = (char *) new + sizeof(*new);
332 memcpy(new->version, work, version_length);
333 AST_RWLIST_WRLOCK(&file_versions);
334 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
335 AST_RWLIST_UNLOCK(&file_versions);
338 void ast_unregister_file_version(const char *file)
340 struct file_version *find;
342 AST_RWLIST_WRLOCK(&file_versions);
343 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
344 if (!strcasecmp(find->file, file)) {
345 AST_RWLIST_REMOVE_CURRENT(list);
349 AST_RWLIST_TRAVERSE_SAFE_END;
350 AST_RWLIST_UNLOCK(&file_versions);
356 char *ast_complete_source_filename(const char *partial, int n)
358 struct file_version *find;
359 size_t len = strlen(partial);
363 AST_RWLIST_RDLOCK(&file_versions);
364 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
365 if (!strncasecmp(find->file, partial, len) && ++count > n) {
366 res = ast_strdup(find->file);
370 AST_RWLIST_UNLOCK(&file_versions);
374 /*! \brief Find version for given module name */
375 const char *ast_file_version_find(const char *file)
377 struct file_version *iterator;
379 AST_RWLIST_WRLOCK(&file_versions);
380 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
381 if (!strcasecmp(iterator->file, file))
384 AST_RWLIST_UNLOCK(&file_versions);
386 return iterator->version;
392 struct thread_list_t {
393 AST_RWLIST_ENTRY(thread_list_t) list;
399 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
401 void ast_register_thread(char *name)
403 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
407 new->id = pthread_self();
408 new->lwp = ast_get_tid();
409 new->name = name; /* steal the allocated memory for the thread name */
410 AST_RWLIST_WRLOCK(&thread_list);
411 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
412 AST_RWLIST_UNLOCK(&thread_list);
415 void ast_unregister_thread(void *id)
417 struct thread_list_t *x;
419 AST_RWLIST_WRLOCK(&thread_list);
420 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
421 if ((void *) x->id == id) {
422 AST_RWLIST_REMOVE_CURRENT(list);
426 AST_RWLIST_TRAVERSE_SAFE_END;
427 AST_RWLIST_UNLOCK(&thread_list);
434 /*! \brief Give an overview of core settings */
435 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
443 e->command = "core show settings";
444 e->usage = "Usage: core show settings\n"
445 " Show core misc settings";
451 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
453 ast_cli(a->fd, "\nPBX Core settings\n");
454 ast_cli(a->fd, "-----------------\n");
455 ast_cli(a->fd, " Version: %s\n", ast_get_version());
456 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
458 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
460 ast_cli(a->fd, " Maximum calls: Not set\n");
462 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
464 ast_cli(a->fd, " Maximum open file handles: Not set\n");
465 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
466 ast_cli(a->fd, " Debug level: %d\n", option_debug);
467 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
468 #if defined(HAVE_SYSINFO)
469 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
471 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
472 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
473 ast_cli(a->fd, " Startup time: %s\n", buf);
475 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
476 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
477 ast_cli(a->fd, " Last reload time: %s\n", buf);
479 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);
480 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
481 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
482 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
483 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
484 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
485 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
486 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
487 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
488 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
489 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
491 ast_cli(a->fd, "\n* Subsystems\n");
492 ast_cli(a->fd, " -------------\n");
493 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
494 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
495 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
496 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
498 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
500 ast_cli(a->fd, "\n* Directories\n");
501 ast_cli(a->fd, " -------------\n");
502 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
503 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
504 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
505 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
506 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
507 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
508 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
509 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
510 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
511 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
512 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
513 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
514 ast_cli(a->fd, "\n\n");
518 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
521 struct thread_list_t *cur;
524 e->command = "core show threads";
526 "Usage: core show threads\n"
527 " List threads currently active in the system.\n";
533 AST_RWLIST_RDLOCK(&thread_list);
534 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
535 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
538 AST_RWLIST_UNLOCK(&thread_list);
539 ast_cli(a->fd, "%d threads listed.\n", count);
543 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
545 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
546 * to be based on the new swapctl(2) system call.
548 static int swapmode(int *used, int *total)
550 struct swapent *swdev;
551 int nswap, rnswap, i;
553 nswap = swapctl(SWAP_NSWAP, 0, 0);
557 swdev = ast_calloc(nswap, sizeof(*swdev));
561 rnswap = swapctl(SWAP_STATS, swdev, nswap);
567 /* if rnswap != nswap, then what? */
569 /* Total things up */
571 for (i = 0; i < nswap; i++) {
572 if (swdev[i].se_flags & SWF_ENABLE) {
573 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
574 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
580 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
581 static int swapmode(int *used, int *total)
588 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
589 /*! \brief Give an overview of system statistics */
590 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
592 uint64_t physmem, freeram;
593 uint64_t freeswap = 0;
597 #if defined(HAVE_SYSINFO)
598 struct sysinfo sys_info;
600 uptime = sys_info.uptime / 3600;
601 physmem = sys_info.totalram * sys_info.mem_unit;
602 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
603 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
604 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
605 nprocs = sys_info.procs;
606 #elif defined(HAVE_SYSCTL)
607 static int pageshift;
608 struct vmtotal vmtotal;
609 struct timeval boottime;
611 int mib[2], pagesize, usedswap = 0;
613 /* calculate the uptime by looking at boottime */
616 mib[1] = KERN_BOOTTIME;
617 len = sizeof(boottime);
618 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
619 uptime = now - boottime.tv_sec;
621 uptime = uptime/3600;
622 /* grab total physical memory */
624 #if defined(HW_PHYSMEM64)
625 mib[1] = HW_PHYSMEM64;
629 len = sizeof(physmem);
630 sysctl(mib, 2, &physmem, &len, NULL, 0);
632 pagesize = getpagesize();
634 while (pagesize > 1) {
639 /* we only need the amount of log(2)1024 for our conversion */
645 len = sizeof(vmtotal);
646 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
647 freeram = (vmtotal.t_free << pageshift);
648 /* generate swap usage and totals */
649 swapmode(&usedswap, &totalswap);
650 freeswap = (totalswap - usedswap);
651 /* grab number of processes */
652 #if defined(__OpenBSD__)
654 mib[1] = KERN_NPROCS;
655 len = sizeof(nprocs);
656 sysctl(mib, 2, &nprocs, &len, NULL, 0);
662 e->command = "core show sysinfo";
664 "Usage: core show sysinfo\n"
665 " List current system information.\n";
671 ast_cli(a->fd, "\nSystem Statistics\n");
672 ast_cli(a->fd, "-----------------\n");
673 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
674 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
675 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
676 #if defined(HAVE_SYSINFO)
677 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
679 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
680 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
681 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
683 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
688 struct profile_entry {
690 uint64_t scale; /* if non-zero, values are scaled by this */
696 struct profile_data {
699 struct profile_entry e[0];
702 static struct profile_data *prof_data;
704 /*! \brief allocates a counter with a given name and scale.
705 * \return Returns the identifier of the counter.
707 int ast_add_profile(const char *name, uint64_t scale)
709 int l = sizeof(struct profile_data);
710 int n = 10; /* default entries */
712 if (prof_data == NULL) {
713 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
714 if (prof_data == NULL)
716 prof_data->entries = 0;
717 prof_data->max_size = n;
719 if (prof_data->entries >= prof_data->max_size) {
721 n = prof_data->max_size + 20;
722 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
726 prof_data->max_size = n;
728 n = prof_data->entries++;
729 prof_data->e[n].name = ast_strdup(name);
730 prof_data->e[n].value = 0;
731 prof_data->e[n].events = 0;
732 prof_data->e[n].mark = 0;
733 prof_data->e[n].scale = scale;
737 int64_t ast_profile(int i, int64_t delta)
739 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
741 if (prof_data->e[i].scale > 1)
742 delta /= prof_data->e[i].scale;
743 prof_data->e[i].value += delta;
744 prof_data->e[i].events++;
745 return prof_data->e[i].value;
748 /* The RDTSC instruction was introduced on the Pentium processor and is not
749 * implemented on certain clones, like the Cyrix 586. Hence, the previous
750 * expectation of __i386__ was in error. */
751 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
752 #if defined(__FreeBSD__)
753 #include <machine/cpufunc.h>
755 static __inline uint64_t
760 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
764 #else /* supply a dummy function on other platforms */
765 static __inline uint64_t
772 int64_t ast_mark(int i, int startstop)
774 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
777 prof_data->e[i].mark = rdtsc();
779 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
780 if (prof_data->e[i].scale > 1)
781 prof_data->e[i].mark /= prof_data->e[i].scale;
782 prof_data->e[i].value += prof_data->e[i].mark;
783 prof_data->e[i].events++;
785 return prof_data->e[i].mark;
788 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
789 max = prof_data->entries;\
790 if (a->argc > 3) { /* specific entries */ \
791 if (isdigit(a->argv[3][0])) { \
792 min = atoi(a->argv[3]); \
793 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
794 max = atoi(a->argv[4]); \
796 search = a->argv[3]; \
798 if (max > prof_data->entries) \
799 max = prof_data->entries;
801 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
804 const char *search = NULL;
807 e->command = "core show profile";
808 e->usage = "Usage: core show profile\n"
809 " show profile information";
815 if (prof_data == NULL)
818 DEFINE_PROFILE_MIN_MAX_VALUES;
819 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
820 prof_data->entries, prof_data->max_size);
821 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
822 "Value", "Average", "Name");
823 for (i = min; i < max; i++) {
824 struct profile_entry *entry = &prof_data->e[i];
825 if (!search || strstr(entry->name, search))
826 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
829 (long)entry->events, (long long)entry->value,
830 (long long)(entry->events ? entry->value / entry->events : entry->value),
836 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
839 const char *search = NULL;
842 e->command = "core clear profile";
843 e->usage = "Usage: core clear profile\n"
844 " clear profile information";
850 if (prof_data == NULL)
853 DEFINE_PROFILE_MIN_MAX_VALUES;
854 for (i= min; i < max; i++) {
855 if (!search || strstr(prof_data->e[i].name, search)) {
856 prof_data->e[i].value = 0;
857 prof_data->e[i].events = 0;
862 #undef DEFINE_PROFILE_MIN_MAX_VALUES
864 /*! \brief CLI command to list module versions */
865 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
867 #define FORMAT "%-25.25s %-40.40s\n"
868 struct file_version *iterator;
874 int matchlen, which = 0;
875 struct file_version *find;
879 e->command = "core show file version [like]";
881 "Usage: core show file version [like <pattern>]\n"
882 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
883 " Optional regular expression pattern is used to filter the file list.\n";
886 matchlen = strlen(a->word);
889 AST_RWLIST_RDLOCK(&file_versions);
890 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
891 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
892 ret = ast_strdup(find->file);
896 AST_RWLIST_UNLOCK(&file_versions);
903 if (!strcasecmp(a->argv[4], "like")) {
904 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
905 return CLI_SHOWUSAGE;
908 return CLI_SHOWUSAGE;
916 return CLI_SHOWUSAGE;
919 ast_cli(a->fd, FORMAT, "File", "Revision");
920 ast_cli(a->fd, FORMAT, "----", "--------");
921 AST_RWLIST_RDLOCK(&file_versions);
922 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
923 if (havename && strcasecmp(iterator->file, a->argv[4]))
926 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
929 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
934 AST_RWLIST_UNLOCK(&file_versions);
936 ast_cli(a->fd, "%d files listed.\n", count_files);
946 #endif /* ! LOW_MEMORY */
948 int ast_register_atexit(void (*func)(void))
950 struct ast_atexit *ae;
952 if (!(ae = ast_calloc(1, sizeof(*ae))))
957 ast_unregister_atexit(func);
959 AST_RWLIST_WRLOCK(&atexits);
960 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
961 AST_RWLIST_UNLOCK(&atexits);
966 void ast_unregister_atexit(void (*func)(void))
968 struct ast_atexit *ae = NULL;
970 AST_RWLIST_WRLOCK(&atexits);
971 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
972 if (ae->func == func) {
973 AST_RWLIST_REMOVE_CURRENT(list);
977 AST_RWLIST_TRAVERSE_SAFE_END;
978 AST_RWLIST_UNLOCK(&atexits);
983 /* Sending commands from consoles back to the daemon requires a terminating NULL */
984 static int fdsend(int fd, const char *s)
986 return write(fd, s, strlen(s) + 1);
989 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
990 static int fdprint(int fd, const char *s)
992 return write(fd, s, strlen(s));
995 /*! \brief NULL handler so we can collect the child exit status */
996 static void _null_sig_handler(int sig)
1000 static struct sigaction null_sig_handler = {
1001 .sa_handler = _null_sig_handler,
1002 .sa_flags = SA_RESTART,
1005 static struct sigaction ignore_sig_handler = {
1006 .sa_handler = SIG_IGN,
1009 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1010 /*! \brief Keep track of how many threads are currently trying to wait*() on
1011 * a child process */
1012 static unsigned int safe_system_level = 0;
1013 static struct sigaction safe_system_prev_handler;
1015 void ast_replace_sigchld(void)
1019 ast_mutex_lock(&safe_system_lock);
1020 level = safe_system_level++;
1022 /* only replace the handler if it has not already been done */
1024 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1027 ast_mutex_unlock(&safe_system_lock);
1030 void ast_unreplace_sigchld(void)
1034 ast_mutex_lock(&safe_system_lock);
1035 level = --safe_system_level;
1037 /* only restore the handler if we are the last one */
1039 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1042 ast_mutex_unlock(&safe_system_lock);
1045 int ast_safe_system(const char *s)
1049 struct rusage rusage;
1052 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1053 ast_replace_sigchld();
1055 #ifdef HAVE_WORKING_FORK
1063 cap_t cap = cap_from_text("cap_net_admin-eip");
1065 if (cap_set_proc(cap)) {
1066 /* Careful with order! Logging cannot happen after we close FDs */
1067 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1071 #ifdef HAVE_WORKING_FORK
1072 if (ast_opt_high_priority)
1073 ast_set_priority(0);
1074 /* Close file descriptors and launch system command */
1075 ast_close_fds_above_n(STDERR_FILENO);
1077 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1079 } else if (pid > 0) {
1081 res = wait4(pid, &status, 0, &rusage);
1083 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1085 } else if (errno != EINTR)
1089 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1093 ast_unreplace_sigchld();
1094 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1102 * \brief enable or disable a logging level to a specified console
1104 void ast_console_toggle_loglevel(int fd, int level, int state)
1108 if (level >= NUMLOGLEVELS) {
1109 level = NUMLOGLEVELS - 1;
1112 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1113 if (fd == consoles[x].fd) {
1115 * Since the logging occurs when levels are false, set to
1116 * flipped iinput because this function accepts 0 as off and 1 as on
1118 consoles[x].levels[level] = state ? 0 : 1;
1125 * \brief mute or unmute a console from logging
1127 void ast_console_toggle_mute(int fd, int silent)
1130 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1131 if (fd == consoles[x].fd) {
1132 if (consoles[x].mute) {
1133 consoles[x].mute = 0;
1135 ast_cli(fd, "Console is not muted anymore.\n");
1137 consoles[x].mute = 1;
1139 ast_cli(fd, "Console is muted.\n");
1144 ast_cli(fd, "Couldn't find remote console.\n");
1148 * \brief log the string to all attached console clients
1150 static void ast_network_puts_mutable(const char *string, int level)
1153 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1154 if (consoles[x].mute)
1156 if (consoles[x].fd > -1) {
1157 if (!consoles[x].levels[level])
1158 fdprint(consoles[x].p[1], string);
1164 * \brief log the string to the console, and all attached
1167 void ast_console_puts_mutable(const char *string, int level)
1169 fputs(string, stdout);
1171 ast_network_puts_mutable(string, level);
1175 * \brief write the string to all attached console clients
1177 static void ast_network_puts(const char *string)
1180 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1181 if (consoles[x].fd > -1)
1182 fdprint(consoles[x].p[1], string);
1187 * write the string to the console, and all attached
1190 void ast_console_puts(const char *string)
1192 fputs(string, stdout);
1194 ast_network_puts(string);
1197 static void network_verboser(const char *s)
1199 ast_network_puts_mutable(s, __LOG_VERBOSE);
1202 static pthread_t lthread;
1205 * \brief read() function supporting the reception of user credentials.
1207 * \param fd Socket file descriptor.
1208 * \param buffer Receive buffer.
1209 * \param size 'buffer' size.
1210 * \param con Console structure to set received credentials
1211 * \retval -1 on error
1212 * \retval the number of bytes received on success.
1214 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1216 #if defined(SO_PEERCRED)
1217 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1218 #define HAVE_STRUCT_UCRED_UID
1219 struct sockpeercred cred;
1223 socklen_t len = sizeof(cred);
1225 #if defined(HAVE_GETPEEREID)
1233 result = read(fd, buffer, size);
1238 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1239 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1242 #if defined(HAVE_STRUCT_UCRED_UID)
1245 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1248 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1250 #elif defined(HAVE_GETPEEREID)
1251 if (getpeereid(fd, &uid, &gid)) {
1263 static void *netconsole(void *vconsole)
1265 struct console *con = vconsole;
1266 char hostname[MAXHOSTNAMELEN] = "";
1269 const char *end_buf = inbuf + sizeof(inbuf);
1270 char *start_read = inbuf;
1272 struct pollfd fds[2];
1274 if (gethostname(hostname, sizeof(hostname)-1))
1275 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1276 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1277 fdprint(con->fd, outbuf);
1279 fds[0].fd = con->fd;
1280 fds[0].events = POLLIN;
1282 fds[1].fd = con->p[0];
1283 fds[1].events = POLLIN;
1286 res = ast_poll(fds, 2, -1);
1289 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1292 if (fds[0].revents) {
1293 int cmds_read, bytes_read;
1294 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1297 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1298 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1299 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1302 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1303 * NULL and not trailing partial commands. */
1304 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1305 /* No commands were read. We either have a short read on the first command
1306 * with space left, or a command that is too long */
1307 if (start_read + bytes_read < end_buf) {
1308 start_read += bytes_read;
1310 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1315 if (start_read[bytes_read - 1] == '\0') {
1316 /* The read ended on a command boundary, start reading again at the head of inbuf */
1320 /* If we get this far, we have left over characters that have not been processed.
1321 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1322 * We are guaranteed to have at least cmds_read NULLs */
1323 while (cmds_read-- && (start_read = rawmemchr(start_read, '\0'))) {
1326 memmove(inbuf, start_read, end_buf - start_read);
1327 start_read = end_buf - start_read + inbuf;
1329 if (fds[1].revents) {
1330 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1332 ast_log(LOG_ERROR, "read returned %d\n", res);
1335 res = write(con->fd, outbuf, res);
1340 if (!ast_opt_hide_connect) {
1341 ast_verb(3, "Remote UNIX connection disconnected\n");
1351 static void *listener(void *unused)
1353 struct sockaddr_un sunaddr;
1358 struct pollfd fds[1];
1362 fds[0].fd = ast_socket;
1363 fds[0].events = POLLIN;
1364 s = ast_poll(fds, 1, -1);
1365 pthread_testcancel();
1368 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1371 len = sizeof(sunaddr);
1372 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1375 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1377 #if !defined(SO_PASSCRED)
1381 /* turn on socket credentials passing. */
1382 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1383 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1386 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1387 if (consoles[x].fd >= 0) {
1390 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1391 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1392 consoles[x].fd = -1;
1393 fdprint(s, "Server failed to create pipe\n");
1397 flags = fcntl(consoles[x].p[1], F_GETFL);
1398 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1400 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1401 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1402 to know if the user didn't send the credentials. */
1403 consoles[x].uid = -2;
1404 consoles[x].gid = -2;
1405 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1406 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1407 close(consoles[x].p[0]);
1408 close(consoles[x].p[1]);
1409 consoles[x].fd = -1;
1410 fdprint(s, "Server failed to spawn thread\n");
1415 if (x >= AST_MAX_CONNECTS) {
1416 fdprint(s, "No more connections allowed\n");
1417 ast_log(LOG_WARNING, "No more connections allowed\n");
1419 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1420 ast_verb(3, "Remote UNIX connection\n");
1428 static int ast_makesocket(void)
1430 struct sockaddr_un sunaddr;
1436 for (x = 0; x < AST_MAX_CONNECTS; x++)
1437 consoles[x].fd = -1;
1438 unlink(ast_config_AST_SOCKET);
1439 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1440 if (ast_socket < 0) {
1441 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1444 memset(&sunaddr, 0, sizeof(sunaddr));
1445 sunaddr.sun_family = AF_LOCAL;
1446 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1447 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1449 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1454 res = listen(ast_socket, 2);
1456 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1461 if (ast_register_verbose(network_verboser)) {
1462 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1465 ast_pthread_create_background(<hread, NULL, listener, NULL);
1467 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1469 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1470 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1475 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1477 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1478 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1483 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1484 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1486 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1489 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1491 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1492 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1498 static int ast_tryconnect(void)
1500 struct sockaddr_un sunaddr;
1502 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1503 if (ast_consock < 0) {
1504 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1507 memset(&sunaddr, 0, sizeof(sunaddr));
1508 sunaddr.sun_family = AF_LOCAL;
1509 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1510 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1519 /*! \brief Urgent handler
1521 Called by soft_hangup to interrupt the poll, read, or other
1522 system call. We don't actually need to do anything though.
1523 Remember: Cannot EVER ast_log from within a signal handler
1525 static void _urg_handler(int num)
1530 static struct sigaction urg_handler = {
1531 .sa_handler = _urg_handler,
1532 .sa_flags = SA_RESTART,
1535 static void _hup_handler(int num)
1537 int a = 0, save_errno = errno;
1538 printf("Received HUP signal -- Reloading configs\n");
1540 execvp(_argv[0], _argv);
1541 sig_flags.need_reload = 1;
1542 if (sig_alert_pipe[1] != -1) {
1543 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1544 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1550 static struct sigaction hup_handler = {
1551 .sa_handler = _hup_handler,
1552 .sa_flags = SA_RESTART,
1555 static void _child_handler(int sig)
1557 /* Must not ever ast_log or ast_verbose within signal handler */
1558 int n, status, save_errno = errno;
1561 * Reap all dead children -- not just one
1563 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1565 if (n == 0 && option_debug)
1566 printf("Huh? Child handler, but nobody there?\n");
1570 static struct sigaction child_handler = {
1571 .sa_handler = _child_handler,
1572 .sa_flags = SA_RESTART,
1575 /*! \brief Set maximum open files */
1576 static void set_ulimit(int value)
1578 struct rlimit l = {0, 0};
1581 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1588 if (setrlimit(RLIMIT_NOFILE, &l)) {
1589 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1593 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1598 /*! \brief Set an X-term or screen title */
1599 static void set_title(char *text)
1601 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1602 fprintf(stdout, "\033]2;%s\007", text);
1605 static void set_icon(char *text)
1607 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1608 fprintf(stdout, "\033]1;%s\007", text);
1611 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1612 else. If your PBX has heavy activity on it, this is a good thing. */
1613 int ast_set_priority(int pri)
1615 struct sched_param sched;
1616 memset(&sched, 0, sizeof(sched));
1619 sched.sched_priority = 10;
1620 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1621 ast_log(LOG_WARNING, "Unable to set high priority\n");
1624 ast_verb(1, "Set to realtime thread\n");
1626 sched.sched_priority = 0;
1627 /* According to the manpage, these parameters can never fail. */
1628 sched_setscheduler(0, SCHED_OTHER, &sched);
1632 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1633 ast_log(LOG_WARNING, "Unable to set high priority\n");
1636 ast_verb(1, "Set to high priority\n");
1638 /* According to the manpage, these parameters can never fail. */
1639 setpriority(PRIO_PROCESS, 0, 0);
1645 static void ast_run_atexits(void)
1647 struct ast_atexit *ae;
1648 AST_RWLIST_RDLOCK(&atexits);
1649 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1653 AST_RWLIST_UNLOCK(&atexits);
1656 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1657 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1659 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1661 if (can_safely_quit(niceness, restart)) {
1662 really_quit(num, niceness, restart);
1663 /* No one gets here. */
1665 /* It wasn't our time. */
1668 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1670 /* Check if someone else isn't already doing this. */
1671 ast_mutex_lock(&safe_system_lock);
1672 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1673 /* Already in progress and other request was less nice. */
1674 ast_mutex_unlock(&safe_system_lock);
1675 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1678 shuttingdown = niceness;
1679 ast_mutex_unlock(&safe_system_lock);
1681 /* Try to get as many CDRs as possible submitted to the backend engines
1682 * (if in batch mode). really_quit happens to call it again when running
1683 * the atexit handlers, otherwise this would be a bit early. */
1684 ast_cdr_engine_term();
1686 if (niceness == SHUTDOWN_NORMAL) {
1688 /* Begin shutdown routine, hanging up active channels */
1689 ast_begin_shutdown(1);
1690 if (option_verbose && ast_opt_console) {
1691 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1696 /* Wait up to 15 seconds for all channels to go away */
1697 if ((e - s) > 15 || !ast_active_channels() || shuttingdown != niceness) {
1700 /* Sleep 1/10 of a second */
1703 } else if (niceness >= SHUTDOWN_NICE) {
1704 if (niceness != SHUTDOWN_REALLY_NICE) {
1705 ast_begin_shutdown(0);
1707 if (option_verbose && ast_opt_console) {
1708 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1711 if (!ast_active_channels() || shuttingdown != niceness) {
1718 /* Re-acquire lock and check if someone changed the niceness, in which
1719 * case someone else has taken over the shutdown. */
1720 ast_mutex_lock(&safe_system_lock);
1721 if (shuttingdown != niceness) {
1722 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1723 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1725 ast_mutex_unlock(&safe_system_lock);
1728 shuttingdown = SHUTTING_DOWN;
1729 ast_mutex_unlock(&safe_system_lock);
1734 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1736 if (niceness >= SHUTDOWN_NICE) {
1737 ast_module_shutdown();
1740 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1741 char filename[80] = "";
1742 if (getenv("HOME")) {
1743 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1745 if (!ast_strlen_zero(filename)) {
1746 ast_el_write_history(filename);
1748 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1749 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1753 if (el_hist != NULL) {
1754 history_end(el_hist);
1756 } else if (mon_sig_flags == pthread_self()) {
1757 if (consolethread != AST_PTHREADT_NULL) {
1758 pthread_kill(consolethread, SIGURG);
1762 ast_verb(0, "Executing last minute cleanups\n");
1764 /* Called on exit */
1765 ast_verb(0, "Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1766 ast_debug(1, "Asterisk ending (%d).\n", num);
1767 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1768 if (ast_socket > -1) {
1769 pthread_cancel(lthread);
1772 unlink(ast_config_AST_SOCKET);
1774 if (ast_consock > -1)
1776 if (!ast_opt_remote)
1777 unlink(ast_config_AST_PID);
1778 printf("%s", term_quit());
1781 ast_verb(0, "Preparing for Asterisk restart...\n");
1782 /* Mark all FD's for closing on exec */
1783 for (i = 3; i < 32768; i++) {
1784 fcntl(i, F_SETFD, FD_CLOEXEC);
1786 ast_verb(0, "Asterisk is now restarting...\n");
1792 /* If there is a consolethread running send it a SIGHUP
1793 so it can execvp, otherwise we can do it ourselves */
1794 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1795 pthread_kill(consolethread, SIGHUP);
1796 /* Give the signal handler some time to complete */
1799 execvp(_argv[0], _argv);
1809 static void __quit_handler(int num)
1812 sig_flags.need_quit = 1;
1813 if (sig_alert_pipe[1] != -1) {
1814 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1815 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1818 /* There is no need to restore the signal handler here, since the app
1819 * is going to exit */
1822 static void __remote_quit_handler(int num)
1824 sig_flags.need_quit = 1;
1827 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1831 if (!strncmp(s, cmp, strlen(cmp))) {
1832 c = s + strlen(cmp);
1833 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1839 /* These gymnastics are due to platforms which designate char as unsigned by
1840 * default. Level is the negative character -- offset by 1, because \0 is the
1842 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
1843 #define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
1845 static void console_verboser(const char *s)
1848 const char *c = NULL;
1851 if (VERBOSE_HASMAGIC(s)) {
1852 level = VERBOSE_MAGIC2LEVEL(s);
1854 if (level > option_verbose) {
1859 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1860 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1861 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1862 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1871 /* Wake up a poll()ing console */
1872 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
1873 pthread_kill(consolethread, SIGURG);
1877 static int ast_all_zeros(char *s)
1887 static void consolehandler(char *s)
1889 printf("%s", term_end());
1892 /* Called when readline data is available */
1893 if (!ast_all_zeros(s))
1894 ast_el_add_history(s);
1895 /* The real handler for bang */
1898 ast_safe_system(s+1);
1900 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1902 ast_cli_command(STDOUT_FILENO, s);
1905 static int remoteconsolehandler(char *s)
1909 /* Called when readline data is available */
1910 if (!ast_all_zeros(s))
1911 ast_el_add_history(s);
1912 /* The real handler for bang */
1915 ast_safe_system(s+1);
1917 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1919 } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
1920 int old_verbose = option_verbose;
1921 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
1923 if (sscanf(s + 25, "%d", &tmp) != 1) {
1924 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
1926 if (tmp > option_verbose) {
1927 option_verbose = tmp;
1929 if (old_verbose != option_verbose) {
1930 fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
1932 fprintf(stdout, "Verbosity level unchanged.\n");
1936 if (sscanf(s + 17, "%d", &option_verbose) != 1) {
1937 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
1939 if (old_verbose != option_verbose) {
1940 fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
1942 fprintf(stdout, "Verbosity level unchanged.\n");
1947 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1948 (s[4] == '\0' || isspace(s[4]))) {
1949 quit_handler(0, SHUTDOWN_FAST, 0);
1956 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1960 e->command = "core show version";
1962 "Usage: core show version\n"
1963 " Shows Asterisk version information.\n";
1970 return CLI_SHOWUSAGE;
1971 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1972 ast_get_version(), ast_build_user, ast_build_hostname,
1973 ast_build_machine, ast_build_os, ast_build_date);
1978 static int handle_quit(int fd, int argc, char *argv[])
1981 return RESULT_SHOWUSAGE;
1982 quit_handler(0, SHUTDOWN_NORMAL, 0);
1983 return RESULT_SUCCESS;
1987 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1991 e->command = "core stop now";
1993 "Usage: core stop now\n"
1994 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2000 if (a->argc != e->args)
2001 return CLI_SHOWUSAGE;
2002 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2006 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2010 e->command = "core stop gracefully";
2012 "Usage: core stop gracefully\n"
2013 " Causes Asterisk to not accept new calls, and exit when all\n"
2014 " active calls have terminated normally.\n";
2020 if (a->argc != e->args)
2021 return CLI_SHOWUSAGE;
2022 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2026 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2030 e->command = "core stop when convenient";
2032 "Usage: core stop when convenient\n"
2033 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2039 if (a->argc != e->args)
2040 return CLI_SHOWUSAGE;
2041 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2042 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2046 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2050 e->command = "core restart now";
2052 "Usage: core restart now\n"
2053 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2060 if (a->argc != e->args)
2061 return CLI_SHOWUSAGE;
2062 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2066 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2070 e->command = "core restart gracefully";
2072 "Usage: core restart gracefully\n"
2073 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2074 " restart when all active calls have ended.\n";
2080 if (a->argc != e->args)
2081 return CLI_SHOWUSAGE;
2082 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2086 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2090 e->command = "core restart when convenient";
2092 "Usage: core restart when convenient\n"
2093 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2099 if (a->argc != e->args)
2100 return CLI_SHOWUSAGE;
2101 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2102 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2106 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2108 int aborting_shutdown = 0;
2112 e->command = "core abort shutdown";
2114 "Usage: core abort shutdown\n"
2115 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2116 " call operations.\n";
2122 if (a->argc != e->args)
2123 return CLI_SHOWUSAGE;
2125 ast_mutex_lock(&safe_system_lock);
2126 if (shuttingdown >= SHUTDOWN_FAST) {
2127 aborting_shutdown = 1;
2128 shuttingdown = NOT_SHUTTING_DOWN;
2130 ast_mutex_unlock(&safe_system_lock);
2132 if (aborting_shutdown) {
2133 ast_cancel_shutdown();
2138 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2144 "Usage: !<command>\n"
2145 " Executes a given shell command\n";
2153 static const char warranty_lines[] = {
2157 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2158 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2159 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2160 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2161 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2162 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2163 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2164 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2165 "REPAIR OR CORRECTION.\n"
2167 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2168 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2169 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2170 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2171 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2172 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2173 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2174 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2175 "POSSIBILITY OF SUCH DAMAGES.\n"
2178 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2182 e->command = "core show warranty";
2184 "Usage: core show warranty\n"
2185 " Shows the warranty (if any) for this copy of Asterisk.\n";
2191 ast_cli(a->fd, "%s", warranty_lines);
2196 static const char license_lines[] = {
2198 "This program is free software; you can redistribute it and/or modify\n"
2199 "it under the terms of the GNU General Public License version 2 as\n"
2200 "published by the Free Software Foundation.\n"
2202 "This program also contains components licensed under other licenses.\n"
2205 "This program is distributed in the hope that it will be useful,\n"
2206 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2207 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2208 "GNU General Public License for more details.\n"
2210 "You should have received a copy of the GNU General Public License\n"
2211 "along with this program; if not, write to the Free Software\n"
2212 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2215 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2219 e->command = "core show license";
2221 "Usage: core show license\n"
2222 " Shows the license(s) for this copy of Asterisk.\n";
2228 ast_cli(a->fd, "%s", license_lines);
2233 #define ASTERISK_PROMPT "*CLI> "
2235 #define ASTERISK_PROMPT2 "%s*CLI> "
2237 static struct ast_cli_entry cli_asterisk[] = {
2238 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2239 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2240 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2241 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2242 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2243 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2244 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2245 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2246 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2247 AST_CLI_DEFINE(handle_version, "Display version info"),
2248 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2249 #if !defined(LOW_MEMORY)
2250 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2251 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2252 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2253 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2255 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2256 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2257 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2258 #endif /* ! LOW_MEMORY */
2261 struct el_read_char_state_struct {
2262 unsigned int line_full:1;
2263 unsigned int prev_line_full:1;
2264 char prev_line_verbosity;
2267 static int el_read_char_state_init(void *ptr)
2269 struct el_read_char_state_struct *state = ptr;
2270 state->line_full = 1;
2271 state->prev_line_full = 1;
2272 state->prev_line_verbosity = 0;
2276 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2278 static int ast_el_read_char(EditLine *editline, char *cp)
2282 struct pollfd fds[2];
2285 #define EL_BUF_SIZE 512
2286 char buf[EL_BUF_SIZE];
2287 struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2291 fds[0].fd = ast_consock;
2292 fds[0].events = POLLIN;
2293 if (!ast_opt_exec) {
2294 fds[1].fd = STDIN_FILENO;
2295 fds[1].events = POLLIN;
2298 res = ast_poll(fds, max, -1);
2300 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2304 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2308 if (!ast_opt_exec && fds[1].revents) {
2309 num_read = read(STDIN_FILENO, cp, 1);
2316 if (fds[0].revents) {
2318 char *curline = buf, *nextline;
2319 res = read(ast_consock, buf, sizeof(buf) - 1);
2320 /* if the remote side disappears exit */
2322 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2323 if (!ast_opt_reconnect) {
2324 quit_handler(0, SHUTDOWN_FAST, 0);
2327 int reconnects_per_second = 20;
2328 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2329 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2330 if (ast_tryconnect()) {
2331 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2332 printf("%s", term_quit());
2335 fdsend(ast_consock, "logger mute silent");
2337 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2340 usleep(1000000 / reconnects_per_second);
2342 if (tries >= 30 * reconnects_per_second) {
2343 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2344 quit_handler(0, SHUTDOWN_FAST, 0);
2352 /* Write over the CLI prompt */
2353 if (!ast_opt_exec && !lastpos) {
2354 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2359 state->prev_line_full = state->line_full;
2360 if ((nextline = strchr(curline, '\n'))) {
2361 state->line_full = 1;
2364 state->line_full = 0;
2365 nextline = strchr(curline, '\0');
2368 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2369 level = VERBOSE_MAGIC2LEVEL(curline);
2371 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2372 /* Non-verbose output */
2375 level = state->prev_line_verbosity;
2377 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2378 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2382 state->prev_line_verbosity = level;
2384 } while (!ast_strlen_zero(curline));
2386 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2398 static struct ast_str *prompt = NULL;
2400 static char *cli_prompt(EditLine *editline)
2405 static int cli_prompt_changes = 0;
2410 if (prompt == NULL) {
2411 prompt = ast_str_create(100);
2412 } else if (!cli_prompt_changes) {
2413 return ast_str_buffer(prompt);
2415 ast_str_reset(prompt);
2418 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2420 struct timeval ts = ast_tvnow();
2421 while (*t != '\0') {
2423 char hostname[MAXHOSTNAMELEN] = "";
2425 struct ast_tm tm = { 0, };
2426 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2430 case 'C': /* color */
2432 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2433 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2435 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2436 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2440 /* If the color has been reset correctly, then there's no need to reset it later */
2441 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2443 case 'd': /* date */
2444 if (ast_localtime(&ts, &tm, NULL)) {
2445 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2446 ast_str_append(&prompt, 0, "%s", tmp);
2447 cli_prompt_changes++;
2450 case 'g': /* group */
2451 if ((gr = getgrgid(getgid()))) {
2452 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2455 case 'h': /* hostname */
2456 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2457 ast_str_append(&prompt, 0, "%s", hostname);
2459 ast_str_append(&prompt, 0, "%s", "localhost");
2462 case 'H': /* short hostname */
2463 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2465 if ((dotptr = strchr(hostname, '.'))) {
2468 ast_str_append(&prompt, 0, "%s", hostname);
2470 ast_str_append(&prompt, 0, "%s", "localhost");
2473 #ifdef HAVE_GETLOADAVG
2474 case 'l': /* load avg */
2476 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2478 getloadavg(list, 3);
2479 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2480 cli_prompt_changes++;
2484 case 's': /* Asterisk system name (from asterisk.conf) */
2485 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2487 case 't': /* time */
2488 if (ast_localtime(&ts, &tm, NULL)) {
2489 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2490 ast_str_append(&prompt, 0, "%s", tmp);
2491 cli_prompt_changes++;
2494 case 'u': /* username */
2495 if ((pw = getpwuid(getuid()))) {
2496 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2499 case '#': /* process console or remote? */
2500 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2502 case '%': /* literal % */
2503 ast_str_append(&prompt, 0, "%c", '%');
2505 case '\0': /* % is last character - prevent bug */
2510 ast_str_append(&prompt, 0, "%c", *t);
2515 /* Force colors back to normal at end */
2516 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2518 } else if (remotehostname) {
2519 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2521 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2524 return ast_str_buffer(prompt);
2527 static char **ast_el_strtoarr(char *buf)
2529 char **match_list = NULL, **match_list_tmp, *retstr;
2530 size_t match_list_len;
2534 while ( (retstr = strsep(&buf, " ")) != NULL) {
2536 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2538 if (matches + 1 >= match_list_len) {
2539 match_list_len <<= 1;
2540 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2541 match_list = match_list_tmp;
2544 ast_free(match_list);
2545 return (char **) NULL;
2549 match_list[matches++] = ast_strdup(retstr);
2553 return (char **) NULL;
2555 if (matches >= match_list_len) {
2556 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2557 match_list = match_list_tmp;
2560 ast_free(match_list);
2561 return (char **) NULL;
2565 match_list[matches] = (char *) NULL;
2570 static int ast_el_sort_compare(const void *i1, const void *i2)
2574 s1 = ((char **)i1)[0];
2575 s2 = ((char **)i2)[0];
2577 return strcasecmp(s1, s2);
2580 static int ast_cli_display_match_list(char **matches, int len, int max)
2582 int i, idx, limit, count;
2583 int screenwidth = 0;
2584 int numoutput = 0, numoutputline = 0;
2586 screenwidth = ast_get_termcols(STDOUT_FILENO);
2588 /* find out how many entries can be put on one line, with two spaces between strings */
2589 limit = screenwidth / (max + 2);
2593 /* how many lines of output */
2594 count = len / limit;
2595 if (count * limit < len)
2600 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2602 for (; count > 0; count--) {
2604 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2606 /* Don't print dupes */
2607 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2609 ast_free(matches[idx]);
2610 matches[idx] = NULL;
2616 fprintf(stdout, "%-*s ", max, matches[idx]);
2617 ast_free(matches[idx]);
2618 matches[idx] = NULL;
2620 if (numoutputline > 0)
2621 fprintf(stdout, "\n");
2628 static char *cli_complete(EditLine *editline, int ch)
2634 int retval = CC_ERROR;
2635 char buf[2048], savechr;
2638 LineInfo *lf = (LineInfo *)el_line(editline);
2640 savechr = *(char *)lf->cursor;
2641 *(char *)lf->cursor = '\0';
2642 ptr = (char *)lf->cursor;
2644 while (ptr > lf->buffer) {
2645 if (isspace(*ptr)) {
2653 len = lf->cursor - ptr;
2655 if (ast_opt_remote) {
2656 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2657 fdsend(ast_consock, buf);
2658 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2659 return (char*)(CC_ERROR);
2662 nummatches = atoi(buf);
2664 if (nummatches > 0) {
2666 int mlen = 0, maxmbuf = 2048;
2667 /* Start with a 2048 byte buffer */
2668 if (!(mbuf = ast_malloc(maxmbuf))) {
2669 lf->cursor[0] = savechr;
2670 return (char *)(CC_ERROR);
2672 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2673 fdsend(ast_consock, buf);
2676 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2677 if (mlen + 1024 > maxmbuf) {
2678 /* Every step increment buffer 1024 bytes */
2680 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2681 lf->cursor[0] = savechr;
2682 return (char *)(CC_ERROR);
2685 /* Only read 1024 bytes at a time */
2686 res = read(ast_consock, mbuf + mlen, 1024);
2692 matches = ast_el_strtoarr(mbuf);
2695 matches = (char **) NULL;
2697 char **p, *oldbuf=NULL;
2699 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2700 for (p = matches; p && *p; p++) {
2701 if (!oldbuf || strcmp(*p,oldbuf))
2709 int matches_num, maxlen, match_len;
2711 if (matches[0][0] != '\0') {
2712 el_deletestr(editline, (int) len);
2713 el_insertstr(editline, matches[0]);
2714 retval = CC_REFRESH;
2717 if (nummatches == 1) {
2718 /* Found an exact match */
2719 el_insertstr(editline, " ");
2720 retval = CC_REFRESH;
2722 /* Must be more than one match */
2723 for (i = 1, maxlen = 0; matches[i]; i++) {
2724 match_len = strlen(matches[i]);
2725 if (match_len > maxlen)
2728 matches_num = i - 1;
2729 if (matches_num >1) {
2730 fprintf(stdout, "\n");
2731 ast_cli_display_match_list(matches, nummatches, maxlen);
2732 retval = CC_REDISPLAY;
2734 el_insertstr(editline," ");
2735 retval = CC_REFRESH;
2738 for (i = 0; matches[i]; i++)
2739 ast_free(matches[i]);
2743 lf->cursor[0] = savechr;
2745 return (char *)(long)retval;
2748 static int ast_el_initialize(void)
2751 char *editor, *editrc = getenv("EDITRC");
2753 if (!(editor = getenv("AST_EDITMODE"))) {
2754 if (!(editor = getenv("AST_EDITOR"))) {
2761 if (el_hist != NULL)
2762 history_end(el_hist);
2764 el = el_init("asterisk", stdin, stdout, stderr);
2765 el_set(el, EL_PROMPT, cli_prompt);
2767 el_set(el, EL_EDITMODE, 1);
2768 el_set(el, EL_EDITOR, editor);
2769 el_hist = history_init();
2770 if (!el || !el_hist)
2773 /* setup history with 100 entries */
2774 history(el_hist, &ev, H_SETSIZE, 100);
2776 el_set(el, EL_HIST, history, el_hist);
2778 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2779 /* Bind <tab> to command completion */
2780 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2781 /* Bind ? to command completion */
2782 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2783 /* Bind ^D to redisplay */
2784 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2785 /* Bind Delete to delete char left */
2786 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
2787 /* Bind Home and End to move to line start and end */
2788 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
2789 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
2790 /* Bind C-left and C-right to move by word (not all terminals) */
2791 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
2792 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
2795 el_source(el, editrc);
2801 #define MAX_HISTORY_COMMAND_LENGTH 256
2803 static int ast_el_add_history(char *buf)
2807 if (el_hist == NULL || el == NULL)
2808 ast_el_initialize();
2809 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2811 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2814 static int ast_el_write_history(char *filename)
2818 if (el_hist == NULL || el == NULL)
2819 ast_el_initialize();
2821 return (history(el_hist, &ev, H_SAVE, filename));
2824 static int ast_el_read_history(char *filename)
2826 char buf[MAX_HISTORY_COMMAND_LENGTH];
2830 if (el_hist == NULL || el == NULL)
2831 ast_el_initialize();
2833 if ((f = fopen(filename, "r")) == NULL)
2837 if (!fgets(buf, sizeof(buf), f))
2839 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2841 if (ast_all_zeros(buf))
2843 if ((ret = ast_el_add_history(buf)) == -1)
2851 static void ast_remotecontrol(char *data)
2855 char filename[80] = "";
2860 char *stringp = NULL;
2865 memset(&sig_flags, 0, sizeof(sig_flags));
2866 signal(SIGINT, __remote_quit_handler);
2867 signal(SIGTERM, __remote_quit_handler);
2868 signal(SIGHUP, __remote_quit_handler);
2870 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2871 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2875 char prefix[] = "cli quit after ";
2876 char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
2877 sprintf(tmp, "%s%s", prefix, data);
2878 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2879 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2880 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
2886 hostname = strsep(&stringp, "/");
2887 cpid = strsep(&stringp, "/");
2888 version = strsep(&stringp, "\n");
2890 version = "<Version Unknown>";
2892 strsep(&stringp, ".");
2898 if (!ast_opt_mute) {
2899 fdsend(ast_consock, "logger mute silent");
2901 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2905 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2906 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
2908 fds.fd = ast_consock;
2909 fds.events = POLLIN;
2912 while (ast_poll(&fds, 1, 60000) > 0) {
2913 char buffer[512] = "", *curline = buffer, *nextline;
2914 int not_written = 1;
2916 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
2920 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
2925 prev_linefull = linefull;
2926 if ((nextline = strchr(curline, '\n'))) {
2931 nextline = strchr(curline, '\0');
2934 /* Skip verbose lines */
2935 /* Prev line full? | Line is verbose | Last line verbose? | Print
2936 * TRUE | TRUE* | TRUE | FALSE
2937 * TRUE | TRUE* | FALSE | FALSE
2938 * TRUE | FALSE* | TRUE | TRUE
2939 * TRUE | FALSE* | FALSE | TRUE
2940 * FALSE | TRUE | TRUE* | FALSE
2941 * FALSE | TRUE | FALSE* | TRUE
2942 * FALSE | FALSE | TRUE* | FALSE
2943 * FALSE | FALSE | FALSE* | TRUE
2945 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
2946 prev_line_verbose = 0;
2948 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2949 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
2952 prev_line_verbose = 1;
2955 } while (!ast_strlen_zero(curline));
2957 /* No non-verbose output in 60 seconds. */
2965 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2966 remotehostname = hostname;
2968 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2969 if (el_hist == NULL || el == NULL)
2970 ast_el_initialize();
2972 el_set(el, EL_GETCFN, ast_el_read_char);
2974 if (!ast_strlen_zero(filename))
2975 ast_el_read_history(filename);
2978 ebuf = (char *)el_gets(el, &num);
2980 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
2984 if (!ebuf && write(1, "", 1) < 0)
2987 if (!ast_strlen_zero(ebuf)) {
2988 if (ebuf[strlen(ebuf)-1] == '\n')
2989 ebuf[strlen(ebuf)-1] = '\0';
2990 if (!remoteconsolehandler(ebuf)) {
2991 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2993 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2999 printf("\nDisconnected from Asterisk server\n");
3002 static int show_version(void)
3004 printf("Asterisk %s\n", ast_get_version());
3008 static int show_cli_help(void)
3010 printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3011 printf("Usage: asterisk [OPTIONS]\n");
3012 printf("Valid Options:\n");
3013 printf(" -V Display version number and exit\n");
3014 printf(" -C <configfile> Use an alternate configuration file\n");
3015 printf(" -G <group> Run as a group other than the caller\n");
3016 printf(" -U <user> Run as a user other than the caller\n");
3017 printf(" -c Provide console CLI\n");
3018 printf(" -d Enable extra debugging\n");
3019 #if HAVE_WORKING_FORK
3020 printf(" -f Do not fork\n");
3021 printf(" -F Always fork\n");
3023 printf(" -g Dump core in case of a crash\n");
3024 printf(" -h This help screen\n");
3025 printf(" -i Initialize crypto keys at startup\n");
3026 printf(" -I Enable internal timing if DAHDI timer is available\n");
3027 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
3028 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
3029 printf(" -m Mute debugging and console output on the console\n");
3030 printf(" -n Disable console colorization\n");
3031 printf(" -p Run as pseudo-realtime thread\n");
3032 printf(" -q Quiet mode (suppress output)\n");
3033 printf(" -r Connect to Asterisk on this machine\n");
3034 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
3035 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
3036 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
3037 printf(" belong after they are done\n");
3038 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3039 printf(" of output to the CLI\n");
3040 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
3041 printf(" -x <cmd> Execute command <cmd> (implies -r)\n");
3042 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
3043 printf(" -W Adjust terminal colors to compensate for a light background\n");
3048 static void ast_readconfig(void)
3050 struct ast_config *cfg;
3051 struct ast_variable *v;
3052 char *config = DEFAULT_CONFIG_FILE;
3053 char hostname[MAXHOSTNAMELEN] = "";
3054 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3056 unsigned int dbdir:1;
3057 unsigned int keydir:1;
3060 if (ast_opt_override_config) {
3061 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3062 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
3063 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3065 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3067 /* init with buildtime config */
3068 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3069 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3070 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3071 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3072 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3073 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3074 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3075 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3076 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3077 ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3078 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3079 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3080 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3081 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3083 ast_set_default_eid(&ast_eid_default);
3085 /* no asterisk.conf? no problem, use buildtime config! */
3086 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3090 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3091 if (!strcasecmp(v->name, "astctlpermissions"))
3092 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3093 else if (!strcasecmp(v->name, "astctlowner"))
3094 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3095 else if (!strcasecmp(v->name, "astctlgroup"))
3096 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3097 else if (!strcasecmp(v->name, "astctl"))
3098 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3101 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3102 if (!strcasecmp(v->name, "astetcdir")) {
3103 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3104 } else if (!strcasecmp(v->name, "astspooldir")) {
3105 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3106 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3107 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3108 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3110 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3111 } else if (!strcasecmp(v->name, "astdbdir")) {
3112 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3114 } else if (!strcasecmp(v->name, "astdatadir")) {
3115 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3117 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3118 } else if (!strcasecmp(v->name, "astkeydir")) {
3119 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3121 } else if (!strcasecmp(v->name, "astlogdir")) {
3122 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3123 } else if (!strcasecmp(v->name, "astagidir")) {
3124 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3125 } else if (!strcasecmp(v->name, "astrundir")) {
3126 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3127 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3128 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3129 } else if (!strcasecmp(v->name, "astmoddir")) {
3130 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3131 } else if (!strcasecmp(v->name, "astsbindir")) {
3132 ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3136 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3137 /* verbose level (-v at startup) */
3138 if (!strcasecmp(v->name, "verbose")) {
3139 option_verbose = atoi(v->value);
3140 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3141 } else if (!strcasecmp(v->name, "timestamp")) {
3142 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3143 /* whether or not to support #exec in config files */
3144 } else if (!strcasecmp(v->name, "execincludes")) {
3145 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3146 /* debug level (-d at startup) */
3147 } else if (!strcasecmp(v->name, "debug")) {
3149 if (sscanf(v->value, "%30d", &option_debug) != 1) {