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
26 * This documentation created by the Doxygen project clearly explains the
27 * internals of the Asterisk software. This documentation contains basic
28 * examples, developer documentation, support information, and information
33 * \par Developer Documentation for Asterisk
35 * This is the main developer documentation for Asterisk. It is
36 * generated by running "make progdocs" from the Asterisk source tree.
38 * In addition to the information available on the Asterisk source code,
39 * please see the appendices for information on coding guidelines,
40 * release management, commit policies, and more.
42 * \arg \ref AsteriskArchitecture
44 * \par Additional documentation
47 * \arg \ref ConfigFiles
49 * \section copyright Copyright and Author
51 * Copyright (C) 1999 - 2012, Digium, Inc.
52 * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
53 * of <a href="http://www.digium.com">Digium, Inc</a>.
55 * \author Mark Spencer <markster@digium.com>
57 * See http://www.asterisk.org for more information about
58 * the Asterisk project. Please do not directly contact
59 * any of the maintainers of this project for assistance;
60 * the project provides a web site, mailing lists, and IRC
61 * channels for your use.
63 * \todo Add pages for mailinglists, IRC, etc...
67 * \brief Top level source file for Asterisk - the Open Source PBX.
68 * Implementation of PBX core functions and CLI interface.
72 <support_level>core</support_level>
77 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
79 #include "asterisk/_private.h"
81 #undef sched_setscheduler
90 #include <sys/resource.h>
94 #if defined(HAVE_SYSINFO)
95 #include <sys/sysinfo.h>
96 #elif defined(HAVE_SYSCTL)
97 #include <sys/param.h>
98 #include <sys/sysctl.h>
99 #if !defined(__OpenBSD__)
100 #include <sys/vmmeter.h>
101 #if defined(__FreeBSD__)
102 #include <vm/vm_param.h>
105 #if defined(HAVE_SWAPCTL)
106 #include <sys/swap.h>
110 #include <histedit.h>
113 int daemon(int, int); /* defined in libresolv of all places */
114 #include <sys/loadavg.h>
118 #include <sys/prctl.h>
120 #include <sys/capability.h>
121 #endif /* HAVE_CAP */
124 /* we define here the variables so to better agree on the prototype */
125 #include "asterisk/paths.h"
126 #include "asterisk/network.h"
127 #include "asterisk/cli.h"
128 #include "asterisk/channel.h"
129 #include "asterisk/translate.h"
130 #include "asterisk/features.h"
131 #include "asterisk/acl.h"
132 #include "asterisk/ulaw.h"
133 #include "asterisk/alaw.h"
134 #include "asterisk/callerid.h"
135 #include "asterisk/image.h"
136 #include "asterisk/tdd.h"
137 #include "asterisk/term.h"
138 #include "asterisk/manager.h"
139 #include "asterisk/cdr.h"
140 #include "asterisk/cel.h"
141 #include "asterisk/pbx.h"
142 #include "asterisk/enum.h"
143 #include "asterisk/http.h"
144 #include "asterisk/udptl.h"
145 #include "asterisk/app.h"
146 #include "asterisk/lock.h"
147 #include "asterisk/utils.h"
148 #include "asterisk/file.h"
149 #include "asterisk/io.h"
150 #include "editline/histedit.h"
151 #include "asterisk/config.h"
152 #include "asterisk/ast_version.h"
153 #include "asterisk/linkedlists.h"
154 #include "asterisk/devicestate.h"
155 #include "asterisk/presencestate.h"
156 #include "asterisk/module.h"
157 #include "asterisk/dsp.h"
158 #include "asterisk/buildinfo.h"
159 #include "asterisk/xmldoc.h"
160 #include "asterisk/poll-compat.h"
161 #include "asterisk/ccss.h"
162 #include "asterisk/test.h"
163 #include "asterisk/rtp_engine.h"
164 #include "asterisk/format.h"
165 #include "asterisk/aoc.h"
167 #include "../defaults.h"
173 #define AF_LOCAL AF_UNIX
174 #define PF_LOCAL PF_UNIX
177 #define AST_MAX_CONNECTS 128
180 /*! Default minimum DTMF digit length - 80ms */
181 #define AST_MIN_DTMF_DURATION 80
184 /*! \brief Welcome message when starting a CLI interface */
185 #define WELCOME_MESSAGE \
186 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
187 "Created by Mark Spencer <markster@digium.com>\n" \
188 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
189 "This is free software, with components licensed under the GNU General Public\n" \
190 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
191 "certain conditions. Type 'core show license' for details.\n" \
192 "=========================================================================\n", ast_get_version()) \
194 /*! \defgroup main_options Main Configuration Options
195 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
196 * \arg \ref Config_ast "asterisk.conf"
197 * \note Some of them can be changed in the CLI
201 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
202 struct ast_flags ast_compat = { 0 };
204 int option_verbose; /*!< Verbosity level */
205 int option_debug; /*!< Debug level */
206 double option_maxload; /*!< Max load avg on system */
207 int option_maxcalls; /*!< Max number of active calls */
208 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
209 unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */
210 #if defined(HAVE_SYSINFO)
211 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
216 struct ast_eid ast_eid_default;
218 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
219 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
221 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
222 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
225 int fd; /*!< File descriptor */
226 int p[2]; /*!< Pipe */
227 pthread_t t; /*!< Thread of handler */
228 int mute; /*!< Is the console muted for logs */
229 int uid; /*!< Remote user ID. */
230 int gid; /*!< Remote group ID. */
231 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
236 AST_RWLIST_ENTRY(ast_atexit) list;
239 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
241 struct timeval ast_startuptime;
242 struct timeval ast_lastreloadtime;
244 static History *el_hist;
246 static char *remotehostname;
248 struct console consoles[AST_MAX_CONNECTS];
250 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
252 static int ast_el_add_history(char *);
253 static int ast_el_read_history(char *);
254 static int ast_el_write_history(char *);
257 char config_dir[PATH_MAX];
258 char module_dir[PATH_MAX];
259 char spool_dir[PATH_MAX];
260 char monitor_dir[PATH_MAX];
261 char var_dir[PATH_MAX];
262 char data_dir[PATH_MAX];
263 char log_dir[PATH_MAX];
264 char agi_dir[PATH_MAX];
265 char run_dir[PATH_MAX];
266 char key_dir[PATH_MAX];
268 char config_file[PATH_MAX];
269 char db_path[PATH_MAX];
270 char sbin_dir[PATH_MAX];
271 char pid_path[PATH_MAX];
272 char socket_path[PATH_MAX];
273 char run_user[PATH_MAX];
274 char run_group[PATH_MAX];
275 char system_name[128];
278 static struct _cfg_paths cfg_paths;
280 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
281 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
282 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
283 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
284 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
285 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
286 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
287 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
288 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
289 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
290 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
291 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
293 const char *ast_config_AST_DB = cfg_paths.db_path;
294 const char *ast_config_AST_PID = cfg_paths.pid_path;
295 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
296 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
297 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
298 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
300 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
301 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
302 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
303 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
305 extern unsigned int ast_FD_SETSIZE;
307 static char *_argv[256];
309 NOT_SHUTTING_DOWN = -2,
311 /* Valid values for quit_handler niceness below: */
317 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
318 static int restartnow;
319 static pthread_t consolethread = AST_PTHREADT_NULL;
320 static pthread_t mon_sig_flags;
321 static int canary_pid = 0;
322 static char canary_filename[128];
324 static char randompool[256];
326 static int sig_alert_pipe[2] = { -1, -1 };
328 unsigned int need_reload:1;
329 unsigned int need_quit:1;
330 unsigned int need_quit_handler:1;
333 #if !defined(LOW_MEMORY)
334 struct file_version {
335 AST_RWLIST_ENTRY(file_version) list;
340 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
342 void ast_register_file_version(const char *file, const char *version)
344 struct file_version *new;
346 size_t version_length;
348 work = ast_strdupa(version);
349 work = ast_strip(ast_strip_quoted(work, "$", "$"));
350 version_length = strlen(work) + 1;
352 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
356 new->version = (char *) new + sizeof(*new);
357 memcpy(new->version, work, version_length);
358 AST_RWLIST_WRLOCK(&file_versions);
359 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
360 AST_RWLIST_UNLOCK(&file_versions);
363 void ast_unregister_file_version(const char *file)
365 struct file_version *find;
367 AST_RWLIST_WRLOCK(&file_versions);
368 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
369 if (!strcasecmp(find->file, file)) {
370 AST_RWLIST_REMOVE_CURRENT(list);
374 AST_RWLIST_TRAVERSE_SAFE_END;
375 AST_RWLIST_UNLOCK(&file_versions);
381 char *ast_complete_source_filename(const char *partial, int n)
383 struct file_version *find;
384 size_t len = strlen(partial);
388 AST_RWLIST_RDLOCK(&file_versions);
389 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
390 if (!strncasecmp(find->file, partial, len) && ++count > n) {
391 res = ast_strdup(find->file);
395 AST_RWLIST_UNLOCK(&file_versions);
399 /*! \brief Find version for given module name */
400 const char *ast_file_version_find(const char *file)
402 struct file_version *iterator;
404 AST_RWLIST_WRLOCK(&file_versions);
405 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
406 if (!strcasecmp(iterator->file, file))
409 AST_RWLIST_UNLOCK(&file_versions);
411 return iterator->version;
415 struct thread_list_t {
416 AST_RWLIST_ENTRY(thread_list_t) list;
422 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
424 void ast_register_thread(char *name)
426 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
430 new->id = pthread_self();
431 new->lwp = ast_get_tid();
432 new->name = name; /* steal the allocated memory for the thread name */
433 AST_RWLIST_WRLOCK(&thread_list);
434 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
435 AST_RWLIST_UNLOCK(&thread_list);
438 void ast_unregister_thread(void *id)
440 struct thread_list_t *x;
442 AST_RWLIST_WRLOCK(&thread_list);
443 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
444 if ((void *) x->id == id) {
445 AST_RWLIST_REMOVE_CURRENT(list);
449 AST_RWLIST_TRAVERSE_SAFE_END;
450 AST_RWLIST_UNLOCK(&thread_list);
457 /*! \brief Give an overview of core settings */
458 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
466 e->command = "core show settings";
467 e->usage = "Usage: core show settings\n"
468 " Show core misc settings";
474 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
476 ast_cli(a->fd, "\nPBX Core settings\n");
477 ast_cli(a->fd, "-----------------\n");
478 ast_cli(a->fd, " Version: %s\n", ast_get_version());
479 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
481 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
483 ast_cli(a->fd, " Maximum calls: Not set\n");
485 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
487 ast_cli(a->fd, " Maximum open file handles: Not set\n");
488 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
489 ast_cli(a->fd, " Debug level: %d\n", option_debug);
490 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
491 #if defined(HAVE_SYSINFO)
492 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
494 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
495 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
496 ast_cli(a->fd, " Startup time: %s\n", buf);
498 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
499 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
500 ast_cli(a->fd, " Last reload time: %s\n", buf);
502 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);
503 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
504 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
505 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
506 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
507 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
508 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
509 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
510 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
511 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
512 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
513 ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
515 ast_cli(a->fd, "\n* Subsystems\n");
516 ast_cli(a->fd, " -------------\n");
517 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
518 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
519 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
520 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
522 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
524 ast_cli(a->fd, "\n* Directories\n");
525 ast_cli(a->fd, " -------------\n");
526 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
527 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
528 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
529 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
530 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
531 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
532 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
533 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
534 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
535 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
536 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
537 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
538 ast_cli(a->fd, "\n\n");
542 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
545 struct thread_list_t *cur;
548 e->command = "core show threads";
550 "Usage: core show threads\n"
551 " List threads currently active in the system.\n";
557 AST_RWLIST_RDLOCK(&thread_list);
558 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
559 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
562 AST_RWLIST_UNLOCK(&thread_list);
563 ast_cli(a->fd, "%d threads listed.\n", count);
567 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
569 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
570 * to be based on the new swapctl(2) system call.
572 static int swapmode(int *used, int *total)
574 struct swapent *swdev;
575 int nswap, rnswap, i;
577 nswap = swapctl(SWAP_NSWAP, 0, 0);
581 swdev = ast_calloc(nswap, sizeof(*swdev));
585 rnswap = swapctl(SWAP_STATS, swdev, nswap);
591 /* if rnswap != nswap, then what? */
593 /* Total things up */
595 for (i = 0; i < nswap; i++) {
596 if (swdev[i].se_flags & SWF_ENABLE) {
597 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
598 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
604 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
605 static int swapmode(int *used, int *total)
612 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
613 /*! \brief Give an overview of system statistics */
614 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
616 uint64_t physmem, freeram;
617 uint64_t freeswap = 0;
621 #if defined(HAVE_SYSINFO)
622 struct sysinfo sys_info;
624 uptime = sys_info.uptime / 3600;
625 physmem = sys_info.totalram * sys_info.mem_unit;
626 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
627 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
628 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
629 nprocs = sys_info.procs;
630 #elif defined(HAVE_SYSCTL)
631 static int pageshift;
632 struct vmtotal vmtotal;
633 struct timeval boottime;
635 int mib[2], pagesize, usedswap = 0;
637 /* calculate the uptime by looking at boottime */
640 mib[1] = KERN_BOOTTIME;
641 len = sizeof(boottime);
642 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
643 uptime = now - boottime.tv_sec;
645 uptime = uptime/3600;
646 /* grab total physical memory */
648 #if defined(HW_PHYSMEM64)
649 mib[1] = HW_PHYSMEM64;
653 len = sizeof(physmem);
654 sysctl(mib, 2, &physmem, &len, NULL, 0);
656 pagesize = getpagesize();
658 while (pagesize > 1) {
663 /* we only need the amount of log(2)1024 for our conversion */
669 len = sizeof(vmtotal);
670 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
671 freeram = (vmtotal.t_free << pageshift);
672 /* generate swap usage and totals */
673 swapmode(&usedswap, &totalswap);
674 freeswap = (totalswap - usedswap);
675 /* grab number of processes */
676 #if defined(__OpenBSD__)
678 mib[1] = KERN_NPROCS;
679 len = sizeof(nprocs);
680 sysctl(mib, 2, &nprocs, &len, NULL, 0);
686 e->command = "core show sysinfo";
688 "Usage: core show sysinfo\n"
689 " List current system information.\n";
695 ast_cli(a->fd, "\nSystem Statistics\n");
696 ast_cli(a->fd, "-----------------\n");
697 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
698 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
699 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
700 #if defined(HAVE_SYSINFO)
701 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
703 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
704 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
705 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
707 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
712 struct profile_entry {
714 uint64_t scale; /* if non-zero, values are scaled by this */
720 struct profile_data {
723 struct profile_entry e[0];
726 static struct profile_data *prof_data;
728 /*! \brief allocates a counter with a given name and scale.
729 * \return Returns the identifier of the counter.
731 int ast_add_profile(const char *name, uint64_t scale)
733 int l = sizeof(struct profile_data);
734 int n = 10; /* default entries */
736 if (prof_data == NULL) {
737 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
738 if (prof_data == NULL)
740 prof_data->entries = 0;
741 prof_data->max_size = n;
743 if (prof_data->entries >= prof_data->max_size) {
745 n = prof_data->max_size + 20;
746 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
750 prof_data->max_size = n;
752 n = prof_data->entries++;
753 prof_data->e[n].name = ast_strdup(name);
754 prof_data->e[n].value = 0;
755 prof_data->e[n].events = 0;
756 prof_data->e[n].mark = 0;
757 prof_data->e[n].scale = scale;
761 int64_t ast_profile(int i, int64_t delta)
763 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
765 if (prof_data->e[i].scale > 1)
766 delta /= prof_data->e[i].scale;
767 prof_data->e[i].value += delta;
768 prof_data->e[i].events++;
769 return prof_data->e[i].value;
772 /* The RDTSC instruction was introduced on the Pentium processor and is not
773 * implemented on certain clones, like the Cyrix 586. Hence, the previous
774 * expectation of __i386__ was in error. */
775 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
776 #if defined(__FreeBSD__)
777 #include <machine/cpufunc.h>
779 static __inline uint64_t
784 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
788 #else /* supply a dummy function on other platforms */
789 static __inline uint64_t
796 int64_t ast_mark(int i, int startstop)
798 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
801 prof_data->e[i].mark = rdtsc();
803 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
804 if (prof_data->e[i].scale > 1)
805 prof_data->e[i].mark /= prof_data->e[i].scale;
806 prof_data->e[i].value += prof_data->e[i].mark;
807 prof_data->e[i].events++;
809 return prof_data->e[i].mark;
812 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
813 max = prof_data->entries;\
814 if (a->argc > 3) { /* specific entries */ \
815 if (isdigit(a->argv[3][0])) { \
816 min = atoi(a->argv[3]); \
817 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
818 max = atoi(a->argv[4]); \
820 search = a->argv[3]; \
822 if (max > prof_data->entries) \
823 max = prof_data->entries;
825 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
828 const char *search = NULL;
831 e->command = "core show profile";
832 e->usage = "Usage: core show profile\n"
833 " show profile information";
839 if (prof_data == NULL)
842 DEFINE_PROFILE_MIN_MAX_VALUES;
843 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
844 prof_data->entries, prof_data->max_size);
845 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
846 "Value", "Average", "Name");
847 for (i = min; i < max; i++) {
848 struct profile_entry *entry = &prof_data->e[i];
849 if (!search || strstr(entry->name, search))
850 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
853 (long)entry->events, (long long)entry->value,
854 (long long)(entry->events ? entry->value / entry->events : entry->value),
860 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
863 const char *search = NULL;
866 e->command = "core clear profile";
867 e->usage = "Usage: core clear profile\n"
868 " clear profile information";
874 if (prof_data == NULL)
877 DEFINE_PROFILE_MIN_MAX_VALUES;
878 for (i= min; i < max; i++) {
879 if (!search || strstr(prof_data->e[i].name, search)) {
880 prof_data->e[i].value = 0;
881 prof_data->e[i].events = 0;
886 #undef DEFINE_PROFILE_MIN_MAX_VALUES
888 /*! \brief CLI command to list module versions */
889 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
891 #define FORMAT "%-25.25s %-40.40s\n"
892 struct file_version *iterator;
898 int matchlen, which = 0;
899 struct file_version *find;
903 e->command = "core show file version [like]";
905 "Usage: core show file version [like <pattern>]\n"
906 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
907 " Optional regular expression pattern is used to filter the file list.\n";
910 matchlen = strlen(a->word);
913 AST_RWLIST_RDLOCK(&file_versions);
914 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
915 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
916 ret = ast_strdup(find->file);
920 AST_RWLIST_UNLOCK(&file_versions);
927 if (!strcasecmp(a->argv[4], "like")) {
928 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
929 return CLI_SHOWUSAGE;
932 return CLI_SHOWUSAGE;
940 return CLI_SHOWUSAGE;
943 ast_cli(a->fd, FORMAT, "File", "Revision");
944 ast_cli(a->fd, FORMAT, "----", "--------");
945 AST_RWLIST_RDLOCK(&file_versions);
946 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
947 if (havename && strcasecmp(iterator->file, a->argv[4]))
950 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
953 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
958 AST_RWLIST_UNLOCK(&file_versions);
960 ast_cli(a->fd, "%d files listed.\n", count_files);
970 #endif /* ! LOW_MEMORY */
972 int ast_register_atexit(void (*func)(void))
974 struct ast_atexit *ae;
976 if (!(ae = ast_calloc(1, sizeof(*ae))))
981 ast_unregister_atexit(func);
983 AST_RWLIST_WRLOCK(&atexits);
984 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
985 AST_RWLIST_UNLOCK(&atexits);
990 void ast_unregister_atexit(void (*func)(void))
992 struct ast_atexit *ae = NULL;
994 AST_RWLIST_WRLOCK(&atexits);
995 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
996 if (ae->func == func) {
997 AST_RWLIST_REMOVE_CURRENT(list);
1001 AST_RWLIST_TRAVERSE_SAFE_END;
1002 AST_RWLIST_UNLOCK(&atexits);
1007 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1008 static int fdsend(int fd, const char *s)
1010 return write(fd, s, strlen(s) + 1);
1013 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1014 static int fdprint(int fd, const char *s)
1016 return write(fd, s, strlen(s));
1019 /*! \brief NULL handler so we can collect the child exit status */
1020 static void _null_sig_handler(int sig)
1024 static struct sigaction null_sig_handler = {
1025 .sa_handler = _null_sig_handler,
1026 .sa_flags = SA_RESTART,
1029 static struct sigaction ignore_sig_handler = {
1030 .sa_handler = SIG_IGN,
1033 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1034 /*! \brief Keep track of how many threads are currently trying to wait*() on
1037 static unsigned int safe_system_level = 0;
1038 static struct sigaction safe_system_prev_handler;
1040 void ast_replace_sigchld(void)
1044 ast_mutex_lock(&safe_system_lock);
1045 level = safe_system_level++;
1047 /* only replace the handler if it has not already been done */
1049 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1052 ast_mutex_unlock(&safe_system_lock);
1055 void ast_unreplace_sigchld(void)
1059 ast_mutex_lock(&safe_system_lock);
1060 level = --safe_system_level;
1062 /* only restore the handler if we are the last one */
1064 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1067 ast_mutex_unlock(&safe_system_lock);
1070 int ast_safe_system(const char *s)
1074 struct rusage rusage;
1077 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1078 ast_replace_sigchld();
1080 #ifdef HAVE_WORKING_FORK
1088 cap_t cap = cap_from_text("cap_net_admin-eip");
1090 if (cap_set_proc(cap)) {
1091 /* Careful with order! Logging cannot happen after we close FDs */
1092 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1096 #ifdef HAVE_WORKING_FORK
1097 if (ast_opt_high_priority)
1098 ast_set_priority(0);
1099 /* Close file descriptors and launch system command */
1100 ast_close_fds_above_n(STDERR_FILENO);
1102 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1104 } else if (pid > 0) {
1106 res = wait4(pid, &status, 0, &rusage);
1108 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1110 } else if (errno != EINTR)
1114 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1118 ast_unreplace_sigchld();
1119 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1127 * \brief enable or disable a logging level to a specified console
1129 void ast_console_toggle_loglevel(int fd, int level, int state)
1133 if (level >= NUMLOGLEVELS) {
1134 level = NUMLOGLEVELS - 1;
1137 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1138 if (fd == consoles[x].fd) {
1140 * Since the logging occurs when levels are false, set to
1141 * flipped iinput because this function accepts 0 as off and 1 as on
1143 consoles[x].levels[level] = state ? 0 : 1;
1150 * \brief mute or unmute a console from logging
1152 void ast_console_toggle_mute(int fd, int silent)
1155 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1156 if (fd == consoles[x].fd) {
1157 if (consoles[x].mute) {
1158 consoles[x].mute = 0;
1160 ast_cli(fd, "Console is not muted anymore.\n");
1162 consoles[x].mute = 1;
1164 ast_cli(fd, "Console is muted.\n");
1169 ast_cli(fd, "Couldn't find remote console.\n");
1173 * \brief log the string to all attached console clients
1175 static void ast_network_puts_mutable(const char *string, int level)
1178 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1179 if (consoles[x].mute)
1181 if (consoles[x].fd > -1) {
1182 if (!consoles[x].levels[level])
1183 fdprint(consoles[x].p[1], string);
1189 * \brief log the string to the console, and all attached
1192 void ast_console_puts_mutable(const char *string, int level)
1194 fputs(string, stdout);
1196 ast_network_puts_mutable(string, level);
1200 * \brief write the string to all attached console clients
1202 static void ast_network_puts(const char *string)
1205 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1206 if (consoles[x].fd > -1)
1207 fdprint(consoles[x].p[1], string);
1212 * \brief write the string to the console, and all attached
1215 void ast_console_puts(const char *string)
1217 fputs(string, stdout);
1219 ast_network_puts(string);
1222 static void network_verboser(const char *s)
1224 ast_network_puts_mutable(s, __LOG_VERBOSE);
1227 static pthread_t lthread;
1230 * \brief read() function supporting the reception of user credentials.
1232 * \param fd Socket file descriptor.
1233 * \param buffer Receive buffer.
1234 * \param size 'buffer' size.
1235 * \param con Console structure to set received credentials
1236 * \retval -1 on error
1237 * \retval the number of bytes received on success.
1239 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1241 #if defined(SO_PEERCRED)
1242 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1243 #define HAVE_STRUCT_UCRED_UID
1244 struct sockpeercred cred;
1248 socklen_t len = sizeof(cred);
1250 #if defined(HAVE_GETPEEREID)
1258 result = read(fd, buffer, size);
1263 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1264 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1267 #if defined(HAVE_STRUCT_UCRED_UID)
1270 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1273 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1275 #elif defined(HAVE_GETPEEREID)
1276 if (getpeereid(fd, &uid, &gid)) {
1288 static void *netconsole(void *vconsole)
1290 struct console *con = vconsole;
1291 char hostname[MAXHOSTNAMELEN] = "";
1294 const char * const end_buf = inbuf + sizeof(inbuf);
1295 char *start_read = inbuf;
1297 struct pollfd fds[2];
1299 if (gethostname(hostname, sizeof(hostname)-1))
1300 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1301 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1302 fdprint(con->fd, outbuf);
1304 fds[0].fd = con->fd;
1305 fds[0].events = POLLIN;
1307 fds[1].fd = con->p[0];
1308 fds[1].events = POLLIN;
1311 res = ast_poll(fds, 2, -1);
1314 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1317 if (fds[0].revents) {
1318 int cmds_read, bytes_read;
1319 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1322 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1323 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1324 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1327 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1328 * NULL and not trailing partial commands. */
1329 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1330 /* No commands were read. We either have a short read on the first command
1331 * with space left, or a command that is too long */
1332 if (start_read + bytes_read < end_buf) {
1333 start_read += bytes_read;
1335 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1340 if (start_read[bytes_read - 1] == '\0') {
1341 /* The read ended on a command boundary, start reading again at the head of inbuf */
1345 /* If we get this far, we have left over characters that have not been processed.
1346 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1347 * We are guaranteed to have at least cmds_read NULLs */
1348 while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1351 memmove(inbuf, start_read, end_buf - start_read);
1352 start_read = end_buf - start_read + inbuf;
1354 if (fds[1].revents) {
1355 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1357 ast_log(LOG_ERROR, "read returned %d\n", res);
1360 res = write(con->fd, outbuf, res);
1365 if (!ast_opt_hide_connect) {
1366 ast_verb(3, "Remote UNIX connection disconnected\n");
1376 static void *listener(void *unused)
1378 struct sockaddr_un sunaddr;
1383 struct pollfd fds[1];
1387 fds[0].fd = ast_socket;
1388 fds[0].events = POLLIN;
1389 s = ast_poll(fds, 1, -1);
1390 pthread_testcancel();
1393 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1396 len = sizeof(sunaddr);
1397 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1400 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1402 #if !defined(SO_PASSCRED)
1406 /* turn on socket credentials passing. */
1407 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1408 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1411 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1412 if (consoles[x].fd >= 0) {
1415 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1416 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1417 consoles[x].fd = -1;
1418 fdprint(s, "Server failed to create pipe\n");
1422 flags = fcntl(consoles[x].p[1], F_GETFL);
1423 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1425 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1426 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1427 to know if the user didn't send the credentials. */
1428 consoles[x].uid = -2;
1429 consoles[x].gid = -2;
1430 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1431 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1432 close(consoles[x].p[0]);
1433 close(consoles[x].p[1]);
1434 consoles[x].fd = -1;
1435 fdprint(s, "Server failed to spawn thread\n");
1440 if (x >= AST_MAX_CONNECTS) {
1441 fdprint(s, "No more connections allowed\n");
1442 ast_log(LOG_WARNING, "No more connections allowed\n");
1444 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1445 ast_verb(3, "Remote UNIX connection\n");
1453 static int ast_makesocket(void)
1455 struct sockaddr_un sunaddr;
1461 for (x = 0; x < AST_MAX_CONNECTS; x++)
1462 consoles[x].fd = -1;
1463 unlink(ast_config_AST_SOCKET);
1464 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1465 if (ast_socket < 0) {
1466 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1469 memset(&sunaddr, 0, sizeof(sunaddr));
1470 sunaddr.sun_family = AF_LOCAL;
1471 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1472 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1474 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1479 res = listen(ast_socket, 2);
1481 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1486 if (ast_register_verbose(network_verboser)) {
1487 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1490 if (ast_pthread_create_background(<hread, NULL, listener, NULL)) {
1491 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1496 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1498 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1499 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1504 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1506 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1507 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1512 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1513 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1515 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1518 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1520 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1521 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1527 static int ast_tryconnect(void)
1529 struct sockaddr_un sunaddr;
1531 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1532 if (ast_consock < 0) {
1533 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1536 memset(&sunaddr, 0, sizeof(sunaddr));
1537 sunaddr.sun_family = AF_LOCAL;
1538 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1539 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1548 /*! \brief Urgent handler
1550 * Called by soft_hangup to interrupt the poll, read, or other
1551 * system call. We don't actually need to do anything though.
1552 * Remember: Cannot EVER ast_log from within a signal handler
1554 static void _urg_handler(int num)
1559 static struct sigaction urg_handler = {
1560 .sa_handler = _urg_handler,
1561 .sa_flags = SA_RESTART,
1564 static void _hup_handler(int num)
1566 int a = 0, save_errno = errno;
1567 printf("Received HUP signal -- Reloading configs\n");
1569 execvp(_argv[0], _argv);
1570 sig_flags.need_reload = 1;
1571 if (sig_alert_pipe[1] != -1) {
1572 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1573 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1579 static struct sigaction hup_handler = {
1580 .sa_handler = _hup_handler,
1581 .sa_flags = SA_RESTART,
1584 static void _child_handler(int sig)
1586 /* Must not ever ast_log or ast_verbose within signal handler */
1587 int n, status, save_errno = errno;
1590 * Reap all dead children -- not just one
1592 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1594 if (n == 0 && option_debug)
1595 printf("Huh? Child handler, but nobody there?\n");
1599 static struct sigaction child_handler = {
1600 .sa_handler = _child_handler,
1601 .sa_flags = SA_RESTART,
1604 /*! \brief Set maximum open files */
1605 static void set_ulimit(int value)
1607 struct rlimit l = {0, 0};
1610 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1617 if (setrlimit(RLIMIT_NOFILE, &l)) {
1618 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1622 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1627 /*! \brief Set an X-term or screen title */
1628 static void set_title(char *text)
1630 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1631 fprintf(stdout, "\033]2;%s\007", text);
1634 static void set_icon(char *text)
1636 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1637 fprintf(stdout, "\033]1;%s\007", text);
1640 /*! \brief We set ourselves to a high priority, that we might pre-empt
1641 * everything else. If your PBX has heavy activity on it, this is a
1644 int ast_set_priority(int pri)
1646 struct sched_param sched;
1647 memset(&sched, 0, sizeof(sched));
1650 sched.sched_priority = 10;
1651 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1652 ast_log(LOG_WARNING, "Unable to set high priority\n");
1655 ast_verb(1, "Set to realtime thread\n");
1657 sched.sched_priority = 0;
1658 /* According to the manpage, these parameters can never fail. */
1659 sched_setscheduler(0, SCHED_OTHER, &sched);
1663 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1664 ast_log(LOG_WARNING, "Unable to set high priority\n");
1667 ast_verb(1, "Set to high priority\n");
1669 /* According to the manpage, these parameters can never fail. */
1670 setpriority(PRIO_PROCESS, 0, 0);
1676 static void ast_run_atexits(void)
1678 struct ast_atexit *ae;
1679 AST_RWLIST_RDLOCK(&atexits);
1680 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1684 AST_RWLIST_UNLOCK(&atexits);
1687 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1688 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1690 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1692 if (can_safely_quit(niceness, restart)) {
1693 really_quit(num, niceness, restart);
1694 /* No one gets here. */
1696 /* It wasn't our time. */
1699 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1701 /* Check if someone else isn't already doing this. */
1702 ast_mutex_lock(&safe_system_lock);
1703 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1704 /* Already in progress and other request was less nice. */
1705 ast_mutex_unlock(&safe_system_lock);
1706 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1709 shuttingdown = niceness;
1710 ast_mutex_unlock(&safe_system_lock);
1712 /* Try to get as many CDRs as possible submitted to the backend engines
1713 * (if in batch mode). really_quit happens to call it again when running
1714 * the atexit handlers, otherwise this would be a bit early. */
1715 ast_cdr_engine_term();
1718 if (niceness == SHUTDOWN_NORMAL) {
1720 /* Begin shutdown routine, hanging up active channels */
1721 ast_begin_shutdown(1);
1722 if (option_verbose && ast_opt_console) {
1723 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1728 /* Wait up to 15 seconds for all channels to go away */
1729 if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1732 /* Sleep 1/10 of a second */
1735 } else if (niceness >= SHUTDOWN_NICE) {
1736 if (niceness != SHUTDOWN_REALLY_NICE) {
1737 ast_begin_shutdown(0);
1739 if (option_verbose && ast_opt_console) {
1740 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1743 if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1750 /* Re-acquire lock and check if someone changed the niceness, in which
1751 * case someone else has taken over the shutdown.
1753 ast_mutex_lock(&safe_system_lock);
1754 if (shuttingdown != niceness) {
1755 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1756 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1758 ast_mutex_unlock(&safe_system_lock);
1761 shuttingdown = SHUTTING_DOWN;
1762 ast_mutex_unlock(&safe_system_lock);
1767 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1769 if (niceness >= SHUTDOWN_NICE) {
1770 ast_module_shutdown();
1773 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1774 char filename[80] = "";
1775 if (getenv("HOME")) {
1776 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1778 if (!ast_strlen_zero(filename)) {
1779 ast_el_write_history(filename);
1781 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1782 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1786 if (el_hist != NULL) {
1787 history_end(el_hist);
1789 } else if (mon_sig_flags == pthread_self()) {
1790 if (consolethread != AST_PTHREADT_NULL) {
1791 pthread_kill(consolethread, SIGURG);
1795 ast_verb(0, "Executing last minute cleanups\n");
1797 /* Called on exit */
1798 ast_verb(0, "Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1799 ast_debug(1, "Asterisk ending (%d).\n", num);
1801 <managerEventInstance>
1802 <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
1804 <parameter name="Shutdown">
1806 <enum name="Uncleanly"/>
1807 <enum name="Cleanly"/>
1810 <parameter name="Restart">
1813 <enum name="False"/>
1817 </managerEventInstance>
1819 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1820 if (ast_socket > -1) {
1821 pthread_cancel(lthread);
1824 unlink(ast_config_AST_SOCKET);
1826 if (ast_consock > -1)
1828 if (!ast_opt_remote)
1829 unlink(ast_config_AST_PID);
1830 printf("%s", term_quit());
1833 ast_verb(0, "Preparing for Asterisk restart...\n");
1834 /* Mark all FD's for closing on exec */
1835 for (i = 3; i < 32768; i++) {
1836 fcntl(i, F_SETFD, FD_CLOEXEC);
1838 ast_verb(0, "Asterisk is now restarting...\n");
1844 /* If there is a consolethread running send it a SIGHUP
1845 so it can execvp, otherwise we can do it ourselves */
1846 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1847 pthread_kill(consolethread, SIGHUP);
1848 /* Give the signal handler some time to complete */
1851 execvp(_argv[0], _argv);
1861 static void __quit_handler(int num)
1864 sig_flags.need_quit = 1;
1865 if (sig_alert_pipe[1] != -1) {
1866 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1867 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1870 /* There is no need to restore the signal handler here, since the app
1871 * is going to exit */
1874 static void __remote_quit_handler(int num)
1876 sig_flags.need_quit = 1;
1879 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1883 if (!strncmp(s, cmp, strlen(cmp))) {
1884 c = s + strlen(cmp);
1885 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1891 /* These gymnastics are due to platforms which designate char as unsigned by
1892 * default. Level is the negative character -- offset by 1, because \0 is the
1894 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
1895 #define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
1897 static void console_verboser(const char *s)
1900 const char *c = NULL;
1903 if (VERBOSE_HASMAGIC(s)) {
1904 level = VERBOSE_MAGIC2LEVEL(s);
1906 if (level > option_verbose) {
1911 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1912 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1913 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1914 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1923 /* Wake up a poll()ing console */
1924 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
1925 pthread_kill(consolethread, SIGURG);
1929 static int ast_all_zeros(char *s)
1939 static void consolehandler(char *s)
1941 printf("%s", term_end());
1944 /* Called when readline data is available */
1945 if (!ast_all_zeros(s))
1946 ast_el_add_history(s);
1947 /* The real handler for bang */
1950 ast_safe_system(s+1);
1952 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1954 ast_cli_command(STDOUT_FILENO, s);
1957 static int remoteconsolehandler(char *s)
1961 /* Called when readline data is available */
1962 if (!ast_all_zeros(s))
1963 ast_el_add_history(s);
1964 /* The real handler for bang */
1967 ast_safe_system(s+1);
1969 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1971 } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
1972 int old_verbose = option_verbose;
1973 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
1975 if (sscanf(s + 25, "%d", &tmp) != 1) {
1976 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
1978 if (tmp > option_verbose) {
1979 option_verbose = tmp;
1981 if (old_verbose != option_verbose) {
1982 fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
1984 fprintf(stdout, "Verbosity level unchanged.\n");
1988 if (sscanf(s + 17, "%d", &option_verbose) != 1) {
1989 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
1991 if (old_verbose != option_verbose) {
1992 fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
1994 fprintf(stdout, "Verbosity level unchanged.\n");
1999 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2000 (s[4] == '\0' || isspace(s[4]))) {
2001 quit_handler(0, SHUTDOWN_FAST, 0);
2008 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2012 e->command = "core show version";
2014 "Usage: core show version\n"
2015 " Shows Asterisk version information.\n";
2022 return CLI_SHOWUSAGE;
2023 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2024 ast_get_version(), ast_build_user, ast_build_hostname,
2025 ast_build_machine, ast_build_os, ast_build_date);
2030 static int handle_quit(int fd, int argc, char *argv[])
2033 return RESULT_SHOWUSAGE;
2034 quit_handler(0, SHUTDOWN_NORMAL, 0);
2035 return RESULT_SUCCESS;
2039 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2043 e->command = "core stop now";
2045 "Usage: core stop now\n"
2046 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2052 if (a->argc != e->args)
2053 return CLI_SHOWUSAGE;
2054 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2058 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2062 e->command = "core stop gracefully";
2064 "Usage: core stop gracefully\n"
2065 " Causes Asterisk to not accept new calls, and exit when all\n"
2066 " active calls have terminated normally.\n";
2072 if (a->argc != e->args)
2073 return CLI_SHOWUSAGE;
2074 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2078 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2082 e->command = "core stop when convenient";
2084 "Usage: core stop when convenient\n"
2085 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2091 if (a->argc != e->args)
2092 return CLI_SHOWUSAGE;
2093 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2094 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2098 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2102 e->command = "core restart now";
2104 "Usage: core restart now\n"
2105 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2112 if (a->argc != e->args)
2113 return CLI_SHOWUSAGE;
2114 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2118 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2122 e->command = "core restart gracefully";
2124 "Usage: core restart gracefully\n"
2125 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2126 " restart when all active calls have ended.\n";
2132 if (a->argc != e->args)
2133 return CLI_SHOWUSAGE;
2134 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2138 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2142 e->command = "core restart when convenient";
2144 "Usage: core restart when convenient\n"
2145 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2151 if (a->argc != e->args)
2152 return CLI_SHOWUSAGE;
2153 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2154 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2158 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2160 int aborting_shutdown = 0;
2164 e->command = "core abort shutdown";
2166 "Usage: core abort shutdown\n"
2167 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2168 " call operations.\n";
2174 if (a->argc != e->args)
2175 return CLI_SHOWUSAGE;
2177 ast_mutex_lock(&safe_system_lock);
2178 if (shuttingdown >= SHUTDOWN_FAST) {
2179 aborting_shutdown = 1;
2180 shuttingdown = NOT_SHUTTING_DOWN;
2182 ast_mutex_unlock(&safe_system_lock);
2184 if (aborting_shutdown) {
2185 ast_cancel_shutdown();
2190 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2196 "Usage: !<command>\n"
2197 " Executes a given shell command\n";
2205 static const char warranty_lines[] = {
2209 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2210 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2211 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2212 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2213 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2214 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2215 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2216 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2217 "REPAIR OR CORRECTION.\n"
2219 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2220 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2221 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2222 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2223 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2224 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2225 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2226 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2227 "POSSIBILITY OF SUCH DAMAGES.\n"
2230 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2234 e->command = "core show warranty";
2236 "Usage: core show warranty\n"
2237 " Shows the warranty (if any) for this copy of Asterisk.\n";
2243 ast_cli(a->fd, "%s", warranty_lines);
2248 static const char license_lines[] = {
2250 "This program is free software; you can redistribute it and/or modify\n"
2251 "it under the terms of the GNU General Public License version 2 as\n"
2252 "published by the Free Software Foundation.\n"
2254 "This program also contains components licensed under other licenses.\n"
2257 "This program is distributed in the hope that it will be useful,\n"
2258 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2259 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2260 "GNU General Public License for more details.\n"
2262 "You should have received a copy of the GNU General Public License\n"
2263 "along with this program; if not, write to the Free Software\n"
2264 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2267 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2271 e->command = "core show license";
2273 "Usage: core show license\n"
2274 " Shows the license(s) for this copy of Asterisk.\n";
2280 ast_cli(a->fd, "%s", license_lines);
2285 #define ASTERISK_PROMPT "*CLI> "
2287 #define ASTERISK_PROMPT2 "%s*CLI> "
2289 static struct ast_cli_entry cli_asterisk[] = {
2290 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2291 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2292 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2293 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2294 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2295 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2296 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2297 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2298 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2299 AST_CLI_DEFINE(handle_version, "Display version info"),
2300 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2301 #if !defined(LOW_MEMORY)
2302 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2303 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2304 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2305 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2307 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2308 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2309 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2310 #endif /* ! LOW_MEMORY */
2313 struct el_read_char_state_struct {
2314 unsigned int line_full:1;
2315 unsigned int prev_line_full:1;
2316 char prev_line_verbosity;
2319 static int el_read_char_state_init(void *ptr)
2321 struct el_read_char_state_struct *state = ptr;
2322 state->line_full = 1;
2323 state->prev_line_full = 1;
2324 state->prev_line_verbosity = 0;
2328 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2330 static int ast_el_read_char(EditLine *editline, char *cp)
2334 struct pollfd fds[2];
2337 #define EL_BUF_SIZE 512
2338 char buf[EL_BUF_SIZE];
2339 struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2343 fds[0].fd = ast_consock;
2344 fds[0].events = POLLIN;
2345 if (!ast_opt_exec) {
2346 fds[1].fd = STDIN_FILENO;
2347 fds[1].events = POLLIN;
2350 res = ast_poll(fds, max, -1);
2352 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2356 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2360 if (!ast_opt_exec && fds[1].revents) {
2361 num_read = read(STDIN_FILENO, cp, 1);
2368 if (fds[0].revents) {
2370 char *curline = buf, *nextline;
2371 res = read(ast_consock, buf, sizeof(buf) - 1);
2372 /* if the remote side disappears exit */
2374 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2375 if (!ast_opt_reconnect) {
2376 quit_handler(0, SHUTDOWN_FAST, 0);
2379 int reconnects_per_second = 20;
2380 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2381 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2382 if (ast_tryconnect()) {
2383 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2384 printf("%s", term_quit());
2387 fdsend(ast_consock, "logger mute silent");
2389 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2392 usleep(1000000 / reconnects_per_second);
2394 if (tries >= 30 * reconnects_per_second) {
2395 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2396 quit_handler(0, SHUTDOWN_FAST, 0);
2404 /* Write over the CLI prompt */
2405 if (!ast_opt_exec && !lastpos) {
2406 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2411 state->prev_line_full = state->line_full;
2412 if ((nextline = strchr(curline, '\n'))) {
2413 state->line_full = 1;
2416 state->line_full = 0;
2417 nextline = strchr(curline, '\0');
2420 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2421 level = VERBOSE_MAGIC2LEVEL(curline);
2423 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2424 /* Non-verbose output */
2427 level = state->prev_line_verbosity;
2429 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2430 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2434 state->prev_line_verbosity = level;
2436 } while (!ast_strlen_zero(curline));
2438 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2450 static struct ast_str *prompt = NULL;
2452 static char *cli_prompt(EditLine *editline)
2457 static int cli_prompt_changes = 0;
2462 if (prompt == NULL) {
2463 prompt = ast_str_create(100);
2464 } else if (!cli_prompt_changes) {
2465 return ast_str_buffer(prompt);
2467 ast_str_reset(prompt);
2470 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2472 struct timeval ts = ast_tvnow();
2473 while (*t != '\0') {
2475 char hostname[MAXHOSTNAMELEN] = "";
2477 struct ast_tm tm = { 0, };
2478 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2482 case 'C': /* color */
2484 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2485 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2487 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2488 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2492 /* If the color has been reset correctly, then there's no need to reset it later */
2493 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2495 case 'd': /* date */
2496 if (ast_localtime(&ts, &tm, NULL)) {
2497 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2498 ast_str_append(&prompt, 0, "%s", tmp);
2499 cli_prompt_changes++;
2502 case 'g': /* group */
2503 if ((gr = getgrgid(getgid()))) {
2504 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2507 case 'h': /* hostname */
2508 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2509 ast_str_append(&prompt, 0, "%s", hostname);
2511 ast_str_append(&prompt, 0, "%s", "localhost");
2514 case 'H': /* short hostname */
2515 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2517 if ((dotptr = strchr(hostname, '.'))) {
2520 ast_str_append(&prompt, 0, "%s", hostname);
2522 ast_str_append(&prompt, 0, "%s", "localhost");
2525 #ifdef HAVE_GETLOADAVG
2526 case 'l': /* load avg */
2528 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2530 getloadavg(list, 3);
2531 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2532 cli_prompt_changes++;
2536 case 's': /* Asterisk system name (from asterisk.conf) */
2537 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2539 case 't': /* time */
2540 if (ast_localtime(&ts, &tm, NULL)) {
2541 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2542 ast_str_append(&prompt, 0, "%s", tmp);
2543 cli_prompt_changes++;
2546 case 'u': /* username */
2547 if ((pw = getpwuid(getuid()))) {
2548 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2551 case '#': /* process console or remote? */
2552 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2554 case '%': /* literal % */
2555 ast_str_append(&prompt, 0, "%c", '%');
2557 case '\0': /* % is last character - prevent bug */
2562 ast_str_append(&prompt, 0, "%c", *t);
2567 /* Force colors back to normal at end */
2568 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2570 } else if (remotehostname) {
2571 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2573 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2576 return ast_str_buffer(prompt);
2579 static char **ast_el_strtoarr(char *buf)
2581 char **match_list = NULL, **match_list_tmp, *retstr;
2582 size_t match_list_len;
2586 while ( (retstr = strsep(&buf, " ")) != NULL) {
2588 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2590 if (matches + 1 >= match_list_len) {
2591 match_list_len <<= 1;
2592 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2593 match_list = match_list_tmp;
2596 ast_free(match_list);
2597 return (char **) NULL;
2601 match_list[matches++] = ast_strdup(retstr);
2605 return (char **) NULL;
2607 if (matches >= match_list_len) {
2608 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2609 match_list = match_list_tmp;
2612 ast_free(match_list);
2613 return (char **) NULL;
2617 match_list[matches] = (char *) NULL;
2622 static int ast_el_sort_compare(const void *i1, const void *i2)
2626 s1 = ((char **)i1)[0];
2627 s2 = ((char **)i2)[0];
2629 return strcasecmp(s1, s2);
2632 static int ast_cli_display_match_list(char **matches, int len, int max)
2634 int i, idx, limit, count;
2635 int screenwidth = 0;
2636 int numoutput = 0, numoutputline = 0;
2638 screenwidth = ast_get_termcols(STDOUT_FILENO);
2640 /* find out how many entries can be put on one line, with two spaces between strings */
2641 limit = screenwidth / (max + 2);
2645 /* how many lines of output */
2646 count = len / limit;
2647 if (count * limit < len)
2652 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2654 for (; count > 0; count--) {
2656 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2658 /* Don't print dupes */
2659 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2661 ast_free(matches[idx]);
2662 matches[idx] = NULL;
2668 fprintf(stdout, "%-*s ", max, matches[idx]);
2669 ast_free(matches[idx]);
2670 matches[idx] = NULL;
2672 if (numoutputline > 0)
2673 fprintf(stdout, "\n");
2680 static char *cli_complete(EditLine *editline, int ch)
2686 int retval = CC_ERROR;
2687 char buf[2048], savechr;
2690 LineInfo *lf = (LineInfo *)el_line(editline);
2692 savechr = *(char *)lf->cursor;
2693 *(char *)lf->cursor = '\0';
2694 ptr = (char *)lf->cursor;
2696 while (ptr > lf->buffer) {
2697 if (isspace(*ptr)) {
2705 len = lf->cursor - ptr;
2707 if (ast_opt_remote) {
2708 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2709 fdsend(ast_consock, buf);
2710 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2711 return (char*)(CC_ERROR);
2714 nummatches = atoi(buf);
2716 if (nummatches > 0) {
2718 int mlen = 0, maxmbuf = 2048;
2719 /* Start with a 2048 byte buffer */
2720 if (!(mbuf = ast_malloc(maxmbuf))) {
2721 *((char *) lf->cursor) = savechr;
2722 return (char *)(CC_ERROR);
2724 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2725 fdsend(ast_consock, buf);
2728 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2729 if (mlen + 1024 > maxmbuf) {
2730 /* Every step increment buffer 1024 bytes */
2732 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2733 *((char *) lf->cursor) = savechr;
2734 return (char *)(CC_ERROR);
2737 /* Only read 1024 bytes at a time */
2738 res = read(ast_consock, mbuf + mlen, 1024);
2744 matches = ast_el_strtoarr(mbuf);
2747 matches = (char **) NULL;
2749 char **p, *oldbuf=NULL;
2751 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2752 for (p = matches; p && *p; p++) {
2753 if (!oldbuf || strcmp(*p,oldbuf))
2761 int matches_num, maxlen, match_len;
2763 if (matches[0][0] != '\0') {
2764 el_deletestr(editline, (int) len);
2765 el_insertstr(editline, matches[0]);
2766 retval = CC_REFRESH;
2769 if (nummatches == 1) {
2770 /* Found an exact match */
2771 el_insertstr(editline, " ");
2772 retval = CC_REFRESH;
2774 /* Must be more than one match */
2775 for (i = 1, maxlen = 0; matches[i]; i++) {
2776 match_len = strlen(matches[i]);
2777 if (match_len > maxlen)
2780 matches_num = i - 1;
2781 if (matches_num >1) {
2782 fprintf(stdout, "\n");
2783 ast_cli_display_match_list(matches, nummatches, maxlen);
2784 retval = CC_REDISPLAY;
2786 el_insertstr(editline," ");
2787 retval = CC_REFRESH;
2790 for (i = 0; matches[i]; i++)
2791 ast_free(matches[i]);
2795 *((char *) lf->cursor) = savechr;
2797 return (char *)(long)retval;
2800 static int ast_el_initialize(void)
2803 char *editor, *editrc = getenv("EDITRC");
2805 if (!(editor = getenv("AST_EDITMODE"))) {
2806 if (!(editor = getenv("AST_EDITOR"))) {
2813 if (el_hist != NULL)
2814 history_end(el_hist);
2816 el = el_init("asterisk", stdin, stdout, stderr);
2817 el_set(el, EL_PROMPT, cli_prompt);
2819 el_set(el, EL_EDITMODE, 1);
2820 el_set(el, EL_EDITOR, editor);
2821 el_hist = history_init();
2822 if (!el || !el_hist)
2825 /* setup history with 100 entries */
2826 history(el_hist, &ev, H_SETSIZE, 100);
2828 el_set(el, EL_HIST, history, el_hist);
2830 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2831 /* Bind <tab> to command completion */
2832 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2833 /* Bind ? to command completion */
2834 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2835 /* Bind ^D to redisplay */
2836 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2837 /* Bind Delete to delete char left */
2838 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
2839 /* Bind Home and End to move to line start and end */
2840 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
2841 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
2842 /* Bind C-left and C-right to move by word (not all terminals) */
2843 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
2844 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
2847 el_source(el, editrc);
2853 #define MAX_HISTORY_COMMAND_LENGTH 256
2855 static int ast_el_add_history(char *buf)
2859 if (el_hist == NULL || el == NULL)
2860 ast_el_initialize();
2861 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2863 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2866 static int ast_el_write_history(char *filename)
2870 if (el_hist == NULL || el == NULL)
2871 ast_el_initialize();
2873 return (history(el_hist, &ev, H_SAVE, filename));
2876 static int ast_el_read_history(char *filename)
2880 if (el_hist == NULL || el == NULL) {
2881 ast_el_initialize();
2884 return history(el_hist, &ev, H_LOAD, filename);
2887 static void ast_remotecontrol(char *data)
2891 char filename[80] = "";
2896 char *stringp = NULL;
2901 memset(&sig_flags, 0, sizeof(sig_flags));
2902 signal(SIGINT, __remote_quit_handler);
2903 signal(SIGTERM, __remote_quit_handler);
2904 signal(SIGHUP, __remote_quit_handler);
2906 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2907 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2911 char prefix[] = "cli quit after ";
2912 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
2913 sprintf(tmp, "%s%s", prefix, data);
2914 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2915 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2916 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
2922 hostname = strsep(&stringp, "/");
2923 cpid = strsep(&stringp, "/");
2924 version = strsep(&stringp, "\n");
2926 version = "<Version Unknown>";
2928 strsep(&stringp, ".");
2934 if (!ast_opt_mute) {
2935 fdsend(ast_consock, "logger mute silent");
2937 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2941 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2942 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
2944 fds.fd = ast_consock;
2945 fds.events = POLLIN;
2948 while (ast_poll(&fds, 1, 60000) > 0) {
2949 char buffer[512] = "", *curline = buffer, *nextline;
2950 int not_written = 1;
2952 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
2956 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
2961 prev_linefull = linefull;
2962 if ((nextline = strchr(curline, '\n'))) {
2967 nextline = strchr(curline, '\0');
2970 /* Skip verbose lines */
2971 /* Prev line full? | Line is verbose | Last line verbose? | Print
2972 * TRUE | TRUE* | TRUE | FALSE
2973 * TRUE | TRUE* | FALSE | FALSE
2974 * TRUE | FALSE* | TRUE | TRUE
2975 * TRUE | FALSE* | FALSE | TRUE
2976 * FALSE | TRUE | TRUE* | FALSE
2977 * FALSE | TRUE | FALSE* | TRUE
2978 * FALSE | FALSE | TRUE* | FALSE
2979 * FALSE | FALSE | FALSE* | TRUE
2981 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
2982 prev_line_verbose = 0;
2984 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2985 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
2988 prev_line_verbose = 1;
2991 } while (!ast_strlen_zero(curline));
2993 /* No non-verbose output in 60 seconds. */
3001 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3002 remotehostname = hostname;
3004 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3005 if (el_hist == NULL || el == NULL)
3006 ast_el_initialize();
3008 el_set(el, EL_GETCFN, ast_el_read_char);
3010 if (!ast_strlen_zero(filename))
3011 ast_el_read_history(filename);
3014 ebuf = (char *)el_gets(el, &num);
3016 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3020 if (!ebuf && write(1, "", 1) < 0)
3023 if (!ast_strlen_zero(ebuf)) {
3024 if (ebuf[strlen(ebuf)-1] == '\n')
3025 ebuf[strlen(ebuf)-1] = '\0';
3026 if (!remoteconsolehandler(ebuf)) {
3027 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3029 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3035 printf("\nDisconnected from Asterisk server\n");
3038 static int show_version(void)
3040 printf("Asterisk %s\n", ast_get_version());
3044 static int show_cli_help(void)
3046 printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3047 printf("Usage: asterisk [OPTIONS]\n");
3048 printf("Valid Options:\n");
3049 printf(" -V Display version number and exit\n");
3050 printf(" -C <configfile> Use an alternate configuration file\n");
3051 printf(" -G <group> Run as a group other than the caller\n");
3052 printf(" -U <user> Run as a user other than the caller\n");
3053 printf(" -c Provide console CLI\n");
3054 printf(" -d Enable extra debugging\n");
3055 #if HAVE_WORKING_FORK
3056 printf(" -f Do not fork\n");
3057 printf(" -F Always fork\n");
3059 printf(" -g Dump core in case of a crash\n");
3060 printf(" -h This help screen\n");
3061 printf(" -i Initialize crypto keys at startup\n");
3062 printf(" -I Enable internal timing if DAHDI timer is available\n");
3063 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
3064 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
3065 printf(" -m Mute debugging and console output on the console\n");
3066 printf(" -n Disable console colorization\n");
3067 printf(" -p Run as pseudo-realtime thread\n");
3068 printf(" -q Quiet mode (suppress output)\n");
3069 printf(" -r Connect to Asterisk on this machine\n");
3070 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
3071 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
3072 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
3073 printf(" belong after they are done\n");
3074 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3075 printf(" of output to the CLI\n");
3076 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
3077 printf(" -x <cmd> Execute command <cmd> (implies -r)\n");
3078 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
3079 printf(" -W Adjust terminal colors to compensate for a light background\n");
3084 static void ast_readconfig(void)
3086 struct ast_config *cfg;
3087 struct ast_variable *v;
3088 char *config = DEFAULT_CONFIG_FILE;
3089 char hostname[MAXHOSTNAMELEN] = "";
3090 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3092 unsigned int dbdir:1;
3093 unsigned int keydir:1;
3096 /* Set default value */
3097 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3099 if (ast_opt_override_config) {
3100 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3101 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
3102 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3104 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3106 /* init with buildtime config */
3107 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3108 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3109 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3110 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3111 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3112 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3113 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3114 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3115 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3116 ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3117 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3118 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3119 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3120 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3122 ast_set_default_eid(&ast_eid_default);
3124 /* no asterisk.conf? no problem, use buildtime config! */
3125 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3129 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3130 if (!strcasecmp(v->name, "astctlpermissions"))
3131 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3132 else if (!strcasecmp(v->name, "astctlowner"))
3133 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3134 else if (!strcasecmp(v->name, "astctlgroup"))
3135 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3136 else if (!strcasecmp(v->name, "astctl"))
3137 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3140 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3141 if (!strcasecmp(v->name, "astetcdir")) {
3142 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3143 } else if (!strcasecmp(v->name, "astspooldir")) {
3144 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3145 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3146 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3147 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3149 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3150 } else if (!strcasecmp(v->name, "astdbdir")) {
3151 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3153 } else if (!strcasecmp(v->name, "astdatadir")) {
3154 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3156 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3157 } else if (!strcasecmp(v->name, "astkeydir")) {
3158 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3160 } else if (!strcasecmp(v->name, "astlogdir")) {
3161 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3162 } else if (!strcasecmp(v->name, "astagidir")) {
3163 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3164 } else if (!strcasecmp(v->name, "astrundir")) {
3165 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3166 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3167 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3168 } else if (!strcasecmp(v->name, "astmoddir")) {
3169 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3170 } else if (!strcasecmp(v->name, "astsbindir")) {
3171 ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3175 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3176 /* verbose level (-v at startup) */
3177 if (!strcasecmp(v->name, "verbose")) {
3178 option_verbose = atoi(v->value);
3179 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3180 } else if (!strcasecmp(v->name, "timestamp")) {
3181 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3182 /* whether or not to support #exec in config files */
3183 } else if (!strcasecmp(v->name, "execincludes")) {
3184 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3185 /* debug level (-d at startup) */
3186 } else if (!strcasecmp(v->name, "debug")) {
3188 if (sscanf(v->value, "%30d", &option_debug) != 1) {
3189 option_debug = ast_true(v->value);
3191 #if HAVE_WORKING_FORK
3192 /* Disable forking (-f at startup) */
3193 } else if (!strcasecmp(v->name, "nofork")) {
3194 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3195 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3196 } else if (!strcasecmp(v->name, "alwaysfork")) {
3197 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3199 /* Run quietly (-q at startup ) */
3200 } else if (!strcasecmp(v->name, "quiet")) {
3201 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3202 /* Run as console (-c at startup, implies nofork) */
3203 } else if (!strcasecmp(v->name, "console")) {
3204 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3205 /* Run with high priority if the O/S permits (-p at startup) */
3206 } else if (!strcasecmp(v->name, "highpriority")) {
3207 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3208 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3209 } else if (!strcasecmp(v->name, "initcrypto")) {
3210 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3211 /* Disable ANSI colors for console (-c at startup) */
3212 } else if (!strcasecmp(v->name, "nocolor")) {
3213 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3214 /* Disable some usage warnings for picky people :p */
3215 } else if (!strcasecmp(v->name, "dontwarn")) {
3216 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3217 /* Dump core in case of crash (-g) */
3218 } else if (!strcasecmp(v->name, "dumpcore")) {
3219 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3220 /* Cache recorded sound files to another directory during recording */
3221 } else if (!strcasecmp(v->name, "cache_record_files")) {
3222 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3223 /* Specify cache directory */
3224 } else if (!strcasecmp(v->name, "record_cache_dir")) {
3225 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3226 /* Build transcode paths via SLINEAR, instead of directly */
3227 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3228 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3229 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3230 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3231 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3232 /* Enable internal timing */
3233 } else if (!strcasecmp(v->name, "internal_timing")) {
3234 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
3235 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3236 if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3237 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3239 } else if (!strcasecmp(v->name, "maxcalls")) {
3240 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3241 option_maxcalls = 0;
3243 } else if (!strcasecmp(v->name, "maxload")) {
3246 if (getloadavg(test, 1) == -1) {
3247 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3248 option_maxload = 0.0;
3249 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3250 option_maxload = 0.0;
3252 /* Set the maximum amount of open files */
3253 } else if (!strcasecmp(v->name, "maxfiles")) {
3254 option_maxfiles = atoi(v->value);
3255 set_ulimit(option_maxfiles);
3256 /* What user to run as */
3257 } else if (!strcasecmp(v->name, "runuser")) {
3258 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3259 /* What group to run as */
3260 } else if (!strcasecmp(v->name, "rungroup")) {
3261 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3262 } else if (!strcasecmp(v->name, "systemname")) {
3263 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3264 } else if (!strcasecmp(v->name, "autosystemname")) {
3265 if (ast_true(v->value)) {
3266 if (!gethostname(hostname, sizeof(hostname) - 1))
3267 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3269 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3270 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3272 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3275 } else if (!strcasecmp(v->name, "languageprefix")) {
3276 ast_language_is_prefix = ast_true(v->value);
3277 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3278 ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
3279 } else if (!strcasecmp(v->name, "lockmode")) {
3280 if (!strcasecmp(v->value, "lockfile")) {
3281 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3282 } else if (!strcasecmp(v->value, "flock")) {
3283 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3285 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3286 "defaulting to 'lockfile'\n", v->value);
3287 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3289 #if defined(HAVE_SYSINFO)
3290 } else if (!strcasecmp(v->name, "minmemfree")) {
3291 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
3292 * if the amount of free memory falls below this watermark */
3293 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3294 option_minmemfree = 0;
3297 } else if (!strcasecmp(v->name, "entityid")) {
3298 struct ast_eid tmp_eid;
3299 if (!ast_str_to_eid(&tmp_eid, v->value)) {
3300 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3301 ast_eid_default = tmp_eid;
3303 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3304 } else if (!strcasecmp(v->name, "lightbackground")) {
3305 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3306 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3307 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3308 } else if (!strcasecmp(v->name, "hideconnect")) {
3309 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3310 } else if (!strcasecmp(v->name, "lockconfdir")) {
3311 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3312 } else if (!strcasecmp(v->name, "stdexten")) {
3313 /* Choose how to invoke the extensions.conf stdexten */
3314 if (!strcasecmp(v->value, "gosub")) {
3315 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3316 } else if (!strcasecmp(v->value, "macro")) {
3317 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3319 ast_log(LOG_WARNING,
3320 "'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
3322 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3326 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3328 if (sscanf(v->value, "%30f", &version) != 1) {
3329 ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3332 if (!strcasecmp(v->name, "app_set")) {
3333 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3334 } else if (!strcasecmp(v->name, "res_agi")) {
3335 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3336 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3337 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3340 ast_config_destroy(cfg);
3343 static void *monitor_sig_flags(void *unused)
3346 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3348 ast_poll(&p, 1, -1);
3349 if (sig_flags.need_reload) {
3350 sig_flags.need_reload = 0;
3351 ast_module_reload(NULL);
3353 if (sig_flags.need_quit) {
3354 sig_flags.need_quit = 0;
3355 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3356 sig_flags.need_quit_handler = 1;
3357 pthread_kill(consolethread, SIGURG);
3359 quit_handler(0, SHUTDOWN_NORMAL, 0);
3362 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3369 static void *canary_thread(void *unused)
3371 struct stat canary_stat;
3374 /* Give the canary time to sing */
3379 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3380 ast_log(LOG_WARNING,
3381 "The canary is no more. He has ceased to be! "
3382 "He's expired and gone to meet his maker! "
3383 "He's a stiff! Bereft of life, he rests in peace. "
3384 "His metabolic processes are now history! He's off the twig! "
3385 "He's kicked the bucket. He's shuffled off his mortal coil, "
3386 "run down the curtain, and joined the bleeding choir invisible!! "
3387 "THIS is an EX-CANARY. (Reducing priority)\n");
3388 ast_set_priority(0);
3392 /* Check the canary once a minute */
3397 /* Used by libc's atexit(3) function */
3398 static void canary_exit(void)
3401 kill(canary_pid, SIGKILL);
3404 static void run_startup_commands(void)
3407 struct ast_config *cfg;
3408 struct ast_flags cfg_flags = { 0 };
3409 struct ast_variable *v;
3411 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3413 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3417 fd = open("/dev/null", O_RDWR);
3419 ast_config_destroy(cfg);
3423 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3424 if (ast_true(v->value))
3425 ast_cli_command(fd, v->name);
3429 ast_config_destroy(cfg);
3432 static void env_init(void)
3434 setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
3435 setenv("AST_BUILD_HOST", ast_build_hostname, 1);
3436 setenv("AST_BUILD_DATE", ast_build_date, 1);
3437 setenv("AST_BUILD_KERNEL", ast_build_kernel, 1);
3438 setenv("AST_BUILD_MACHINE", ast_build_machine, 1);
3439 setenv("AST_BUILD_OS", ast_build_os, 1);
3440 setenv("AST_BUILD_USER", ast_build_user, 1);
3441 setenv("AST_VERSION", ast_get_version(), 1);
3444 int main(int argc, char *argv[])
3447 char filename[80] = "";
3448 char hostname[MAXHOSTNAMELEN] = "";
3455 int isroot = 1, rundir_exists = 0;
3457 const char *runuser = NULL, *rungroup = NULL;
3458 char *remotesock = NULL;
3459 int moduleresult; /*!< Result from the module load subsystem */
3462 /* Remember original args for restart */
3463 if (argc > ARRAY_LEN(_argv) - 1) {
3464 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
3465 argc = ARRAY_LEN(_argv) - 1;
3467 for (x = 0; x < argc; x++)
3474 /* if the progname is rasterisk consider it a remote console */
3475 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
3476 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3478 if (gethostname(hostname, sizeof(hostname)-1))
3479 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
3480 ast_mainpid = getpid();
3484 ast_builtins_init();
3492 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3493 /*! \brief Check for options
3495 * \todo Document these options
3497 while ((c = getopt(argc, argv, "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:")) != -1) {
3498 /*!\note Please keep the ordering here to alphabetical, capital letters
3499 * first. This will make it easier in the future to select unused
3500 * option flags for new features. */
3502 case 'B': /* Force black background */
3503 ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3504 ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);
3507 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES);
3510 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
3511 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
3514 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3518 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3520 #if defined(HAVE_SYSINFO)
3522 if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3523 option_minmemfree = 0;
3527 #if HAVE_WORKING_FORK
3529 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
3532 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
3536 rungroup = ast_strdupa(optarg);
3539 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
3545 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
3548 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
3551 if ((sscanf(optarg, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3552 option_maxload = 0.0;
3556 if ((sscanf(optarg, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3557 option_maxcalls = 0;
3561 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
3564 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
3567 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
3570 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
3573 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
3576 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3579 remotesock = ast_strdupa(optarg);