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
31 * \section community Community
32 * Asterisk is a big project and has a busy community. Look at the
33 * resources for questions and stick around to help answer questions.
34 * \li \ref asterisk_community_resources
36 * \par Developer Documentation for Asterisk
38 * This is the main developer documentation for Asterisk. It is
39 * generated by running "make progdocs" from the Asterisk source tree.
41 * In addition to the information available on the Asterisk source code,
42 * please see the appendices for information on coding guidelines,
43 * release management, commit policies, and more.
45 * \arg \ref AsteriskArchitecture
47 * \par Additional documentation
50 * \arg \ref configuration_file
51 * \arg \ref channel_drivers
52 * \arg \ref applications
54 * \section copyright Copyright and Author
56 * Copyright (C) 1999 - 2012, Digium, Inc.
57 * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
58 * of <a href="http://www.digium.com">Digium, Inc</a>.
60 * \author Mark Spencer <markster@digium.com>
62 * See http://www.asterisk.org for more information about
63 * the Asterisk project. Please do not directly contact
64 * any of the maintainers of this project for assistance;
65 * the project provides a web site, mailing lists, and IRC
66 * channels for your use.
71 * \page asterisk_community_resources Asterisk Community Resources
73 * \li http://www.asterisk.org Asterisk Homepage
74 * \li http://wiki.asterisk.org Asterisk Wiki
78 * All lists: http://lists.digium.com/mailman/listinfo
79 * \li aadk-commits SVN commits to the AADK repository
80 * \li asterisk-addons-commits SVN commits to the Asterisk addons project
81 * \li asterisk-announce [no description available]
82 * \li asterisk-biz Commercial and Business-Oriented Asterisk Discussion
83 * \li Asterisk-BSD Asterisk on BSD discussion
84 * \li asterisk-bugs [no description available]
85 * \li asterisk-commits SVN commits to the Asterisk project
86 * \li asterisk-dev Asterisk Developers Mailing List
87 * \li asterisk-doc Discussions regarding The Asterisk Documentation Project
88 * \li asterisk-embedded Asterisk Embedded Development
89 * \li asterisk-gui Asterisk GUI project discussion
90 * \li asterisk-gui-commits SVN commits to the Asterisk-GUI project
91 * \li asterisk-ha-clustering Asterisk High Availability and Clustering List - Non-Commercial Discussion
92 * \li Asterisk-i18n Discussion of Asterisk internationalization
93 * \li asterisk-r2 [no description available]
94 * \li asterisk-scf-commits Commits to the Asterisk SCF project code repositories
95 * \li asterisk-scf-committee Asterisk SCF Steering Committee discussions
96 * \li asterisk-scf-dev Asterisk SCF Developers Mailing List
97 * \li asterisk-scf-wiki-changes Changes to the Asterisk SCF space on wiki.asterisk.org
98 * \li asterisk-security Asterisk Security Discussion
99 * \li asterisk-speech-rec Use of speech recognition in Asterisk
100 * \li asterisk-ss7 [no description available]
101 * \li asterisk-users Asterisk Users Mailing List - Non-Commercial Discussion
102 * \li asterisk-video Development discussion of video media support in Asterisk
103 * \li asterisk-wiki-changes Changes to the Asterisk space on wiki.asterisk.org
104 * \li asterisknow AsteriskNOW Discussion
105 * \li dahdi-commits SVN commits to the DAHDI project
106 * \li digium-announce Digium Product Announcements
107 * \li Dundi Distributed Universal Number Discovery
108 * \li libiax2-commits SVN commits to the libiax2 project
109 * \li libpri-commits SVN commits to the libpri project
110 * \li libss7-commits SVN commits to the libss7 project
111 * \li svn-commits SVN commits to the Digium repositories
112 * \li Test-results Results from automated testing
113 * \li thirdparty-commits SVN commits to the Digium third-party software repository
114 * \li zaptel-commits SVN commits to the Zaptel project
117 * \li Forums are located at http://forums.asterisk.org/
121 * Use http://www.freenode.net IRC server to connect with Asterisk
122 * developers and users in realtime.
124 * \li \verbatim #asterisk \endverbatim Asterisk Users Room
125 * \li \verbatim #asterisk-dev \endverbatim Asterisk Developers Room
129 * If you would like to add a resource to this list please create an issue
130 * on the issue tracker with a patch.
134 * \brief Top level source file for Asterisk - the Open Source PBX.
135 * Implementation of PBX core functions and CLI interface.
138 /*! \li \ref asterisk.c uses the configuration file \ref asterisk.conf
139 * \addtogroup configuration_file
142 /*! \page asterisk.conf asterisk.conf
143 * \verbinclude asterisk.conf.sample
147 <support_level>core</support_level>
150 #include "asterisk.h"
152 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
154 #include "asterisk/_private.h"
156 #undef sched_setscheduler
158 #include <sys/time.h>
163 #include <sys/wait.h>
165 #include <sys/resource.h>
168 #include <sys/stat.h>
169 #if defined(HAVE_SYSINFO)
170 #include <sys/sysinfo.h>
171 #elif defined(HAVE_SYSCTL)
172 #include <sys/param.h>
173 #include <sys/sysctl.h>
174 #if !defined(__OpenBSD__)
175 #include <sys/vmmeter.h>
176 #if defined(__FreeBSD__)
177 #include <vm/vm_param.h>
180 #if defined(HAVE_SWAPCTL)
181 #include <sys/swap.h>
185 #include <histedit.h>
188 int daemon(int, int); /* defined in libresolv of all places */
189 #include <sys/loadavg.h>
193 #include <sys/prctl.h>
195 #include <sys/capability.h>
196 #endif /* HAVE_CAP */
199 /* we define here the variables so to better agree on the prototype */
200 #include "asterisk/paths.h"
201 #include "asterisk/network.h"
202 #include "asterisk/cli.h"
203 #include "asterisk/channel.h"
204 #include "asterisk/translate.h"
205 #include "asterisk/features.h"
206 #include "asterisk/acl.h"
207 #include "asterisk/ulaw.h"
208 #include "asterisk/alaw.h"
209 #include "asterisk/callerid.h"
210 #include "asterisk/image.h"
211 #include "asterisk/tdd.h"
212 #include "asterisk/term.h"
213 #include "asterisk/manager.h"
214 #include "asterisk/cdr.h"
215 #include "asterisk/cel.h"
216 #include "asterisk/pbx.h"
217 #include "asterisk/enum.h"
218 #include "asterisk/http.h"
219 #include "asterisk/udptl.h"
220 #include "asterisk/app.h"
221 #include "asterisk/lock.h"
222 #include "asterisk/utils.h"
223 #include "asterisk/file.h"
224 #include "asterisk/io.h"
225 #include "editline/histedit.h"
226 #include "asterisk/config.h"
227 #include "asterisk/ast_version.h"
228 #include "asterisk/linkedlists.h"
229 #include "asterisk/devicestate.h"
230 #include "asterisk/presencestate.h"
231 #include "asterisk/module.h"
232 #include "asterisk/dsp.h"
233 #include "asterisk/buildinfo.h"
234 #include "asterisk/xmldoc.h"
235 #include "asterisk/poll-compat.h"
236 #include "asterisk/ccss.h"
237 #include "asterisk/test.h"
238 #include "asterisk/rtp_engine.h"
239 #include "asterisk/format.h"
240 #include "asterisk/aoc.h"
241 #include "asterisk/uuid.h"
242 #include "asterisk/sorcery.h"
243 #include "asterisk/stasis.h"
244 #include "asterisk/json.h"
245 #include "asterisk/stasis_endpoints.h"
246 #include "asterisk/security_events.h"
248 #include "../defaults.h"
251 <managerEvent language="en_US" name="FullyBooted">
252 <managerEventInstance class="EVENT_FLAG_SYSTEM">
253 <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
255 <parameter name="Status">
256 <para>Informational message</para>
259 </managerEventInstance>
261 <managerEvent language="en_US" name="Shutdown">
262 <managerEventInstance class="EVENT_FLAG_SYSTEM">
263 <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
265 <parameter name="Shutdown">
266 <para>Whether the shutdown is proceeding cleanly (all channels
267 were hungup successfully) or uncleanly (channels will be
270 <enum name="Uncleanly"/>
271 <enum name="Cleanly"/>
274 <parameter name="Restart">
275 <para>Whether or not a restart will occur.</para>
282 </managerEventInstance>
287 #define AF_LOCAL AF_UNIX
288 #define PF_LOCAL PF_UNIX
291 #define AST_MAX_CONNECTS 128
294 /*! Default minimum DTMF digit length - 80ms */
295 #define AST_MIN_DTMF_DURATION 80
298 /*! \brief Welcome message when starting a CLI interface */
299 #define WELCOME_MESSAGE \
300 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
301 "Created by Mark Spencer <markster@digium.com>\n" \
302 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
303 "This is free software, with components licensed under the GNU General Public\n" \
304 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
305 "certain conditions. Type 'core show license' for details.\n" \
306 "=========================================================================\n", ast_get_version()) \
308 /*! \defgroup main_options Main Configuration Options
309 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
310 * \arg \ref Config_ast "asterisk.conf"
311 * \note Some of them can be changed in the CLI
315 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
316 struct ast_flags ast_compat = { 0 };
318 int option_verbose; /*!< Verbosity level */
319 int option_debug; /*!< Debug level */
320 double option_maxload; /*!< Max load avg on system */
321 int option_maxcalls; /*!< Max number of active calls */
322 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
323 unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */
324 #if defined(HAVE_SYSINFO)
325 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
330 struct ast_eid ast_eid_default;
332 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
333 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
335 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
336 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
339 int fd; /*!< File descriptor */
340 int p[2]; /*!< Pipe */
341 pthread_t t; /*!< Thread of handler */
342 int mute; /*!< Is the console muted for logs */
343 int uid; /*!< Remote user ID. */
344 int gid; /*!< Remote group ID. */
345 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
350 AST_LIST_ENTRY(ast_atexit) list;
353 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
355 struct timeval ast_startuptime;
356 struct timeval ast_lastreloadtime;
358 static History *el_hist;
360 static char *remotehostname;
362 struct console consoles[AST_MAX_CONNECTS];
364 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
366 static int ast_el_add_history(char *);
367 static int ast_el_read_history(char *);
368 static int ast_el_write_history(char *);
371 char config_dir[PATH_MAX];
372 char module_dir[PATH_MAX];
373 char spool_dir[PATH_MAX];
374 char monitor_dir[PATH_MAX];
375 char var_dir[PATH_MAX];
376 char data_dir[PATH_MAX];
377 char log_dir[PATH_MAX];
378 char agi_dir[PATH_MAX];
379 char run_dir[PATH_MAX];
380 char key_dir[PATH_MAX];
382 char config_file[PATH_MAX];
383 char db_path[PATH_MAX];
384 char sbin_dir[PATH_MAX];
385 char pid_path[PATH_MAX];
386 char socket_path[PATH_MAX];
387 char run_user[PATH_MAX];
388 char run_group[PATH_MAX];
389 char system_name[128];
392 static struct _cfg_paths cfg_paths;
394 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
395 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
396 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
397 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
398 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
399 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
400 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
401 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
402 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
403 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
404 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
405 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
407 const char *ast_config_AST_DB = cfg_paths.db_path;
408 const char *ast_config_AST_PID = cfg_paths.pid_path;
409 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
410 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
411 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
412 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
414 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
415 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
416 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
417 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
419 extern unsigned int ast_FD_SETSIZE;
421 static char *_argv[256];
423 NOT_SHUTTING_DOWN = -2,
425 /* Valid values for quit_handler niceness below: */
431 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
432 static int restartnow;
433 static pthread_t consolethread = AST_PTHREADT_NULL;
434 static pthread_t mon_sig_flags;
435 static int canary_pid = 0;
436 static char canary_filename[128];
437 static int multi_thread_safe;
439 static char randompool[256];
441 static int sig_alert_pipe[2] = { -1, -1 };
443 unsigned int need_reload:1;
444 unsigned int need_quit:1;
445 unsigned int need_quit_handler:1;
448 /*! \brief The \ref stasis topic for system level changes */
449 static struct stasis_topic *system_topic;
451 /*!\ brief The \ref stasis_message_type for network changes */
452 STASIS_MESSAGE_TYPE_DEFN(ast_network_change_type);
454 #if !defined(LOW_MEMORY)
455 struct file_version {
456 AST_RWLIST_ENTRY(file_version) list;
461 /*! \brief The \ref stasis topic for system level changes */
462 static struct stasis_topic *system_topic;
464 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
466 void ast_register_file_version(const char *file, const char *version)
468 struct file_version *new;
470 size_t version_length;
472 work = ast_strdupa(version);
473 work = ast_strip(ast_strip_quoted(work, "$", "$"));
474 version_length = strlen(work) + 1;
476 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
480 new->version = (char *) new + sizeof(*new);
481 memcpy(new->version, work, version_length);
482 AST_RWLIST_WRLOCK(&file_versions);
483 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
484 AST_RWLIST_UNLOCK(&file_versions);
487 void ast_unregister_file_version(const char *file)
489 struct file_version *find;
491 AST_RWLIST_WRLOCK(&file_versions);
492 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
493 if (!strcasecmp(find->file, file)) {
494 AST_RWLIST_REMOVE_CURRENT(list);
498 AST_RWLIST_TRAVERSE_SAFE_END;
499 AST_RWLIST_UNLOCK(&file_versions);
505 char *ast_complete_source_filename(const char *partial, int n)
507 struct file_version *find;
508 size_t len = strlen(partial);
512 AST_RWLIST_RDLOCK(&file_versions);
513 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
514 if (!strncasecmp(find->file, partial, len) && ++count > n) {
515 res = ast_strdup(find->file);
519 AST_RWLIST_UNLOCK(&file_versions);
523 /*! \brief Find version for given module name */
524 const char *ast_file_version_find(const char *file)
526 struct file_version *iterator;
528 AST_RWLIST_WRLOCK(&file_versions);
529 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
530 if (!strcasecmp(iterator->file, file))
533 AST_RWLIST_UNLOCK(&file_versions);
535 return iterator->version;
539 struct thread_list_t {
540 AST_RWLIST_ENTRY(thread_list_t) list;
546 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
548 void ast_register_thread(char *name)
550 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
555 ast_assert(multi_thread_safe);
556 new->id = pthread_self();
557 new->lwp = ast_get_tid();
558 new->name = name; /* steal the allocated memory for the thread name */
559 AST_RWLIST_WRLOCK(&thread_list);
560 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
561 AST_RWLIST_UNLOCK(&thread_list);
564 void ast_unregister_thread(void *id)
566 struct thread_list_t *x;
568 AST_RWLIST_WRLOCK(&thread_list);
569 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
570 if ((void *) x->id == id) {
571 AST_RWLIST_REMOVE_CURRENT(list);
575 AST_RWLIST_TRAVERSE_SAFE_END;
576 AST_RWLIST_UNLOCK(&thread_list);
583 /*! \brief Give an overview of core settings */
584 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
592 e->command = "core show settings";
593 e->usage = "Usage: core show settings\n"
594 " Show core misc settings";
600 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
602 ast_cli(a->fd, "\nPBX Core settings\n");
603 ast_cli(a->fd, "-----------------\n");
604 ast_cli(a->fd, " Version: %s\n", ast_get_version());
605 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
607 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
609 ast_cli(a->fd, " Maximum calls: Not set\n");
611 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
613 ast_cli(a->fd, " Maximum open file handles: Not set\n");
614 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
615 ast_cli(a->fd, " Debug level: %d\n", option_debug);
616 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
617 #if defined(HAVE_SYSINFO)
618 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
620 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
621 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
622 ast_cli(a->fd, " Startup time: %s\n", buf);
624 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
625 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
626 ast_cli(a->fd, " Last reload time: %s\n", buf);
628 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);
629 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
630 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
631 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
632 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
633 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
634 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
635 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
636 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
637 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
638 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
639 ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
641 ast_cli(a->fd, "\n* Subsystems\n");
642 ast_cli(a->fd, " -------------\n");
643 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
644 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
645 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
646 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
648 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
650 ast_cli(a->fd, "\n* Directories\n");
651 ast_cli(a->fd, " -------------\n");
652 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
653 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
654 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
655 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
656 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
657 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
658 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
659 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
660 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
661 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
662 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
663 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
664 ast_cli(a->fd, "\n\n");
668 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
671 struct thread_list_t *cur;
674 e->command = "core show threads";
676 "Usage: core show threads\n"
677 " List threads currently active in the system.\n";
683 AST_RWLIST_RDLOCK(&thread_list);
684 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
685 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
688 AST_RWLIST_UNLOCK(&thread_list);
689 ast_cli(a->fd, "%d threads listed.\n", count);
693 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
695 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
696 * to be based on the new swapctl(2) system call.
698 static int swapmode(int *used, int *total)
700 struct swapent *swdev;
701 int nswap, rnswap, i;
703 nswap = swapctl(SWAP_NSWAP, 0, 0);
707 swdev = ast_calloc(nswap, sizeof(*swdev));
711 rnswap = swapctl(SWAP_STATS, swdev, nswap);
717 /* if rnswap != nswap, then what? */
719 /* Total things up */
721 for (i = 0; i < nswap; i++) {
722 if (swdev[i].se_flags & SWF_ENABLE) {
723 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
724 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
730 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
731 static int swapmode(int *used, int *total)
738 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
739 /*! \brief Give an overview of system statistics */
740 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
742 uint64_t physmem, freeram;
743 uint64_t freeswap = 0;
747 #if defined(HAVE_SYSINFO)
748 struct sysinfo sys_info;
750 uptime = sys_info.uptime / 3600;
751 physmem = sys_info.totalram * sys_info.mem_unit;
752 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
753 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
754 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
755 nprocs = sys_info.procs;
756 #elif defined(HAVE_SYSCTL)
757 static int pageshift;
758 struct vmtotal vmtotal;
759 struct timeval boottime;
761 int mib[2], pagesize, usedswap = 0;
763 /* calculate the uptime by looking at boottime */
766 mib[1] = KERN_BOOTTIME;
767 len = sizeof(boottime);
768 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
769 uptime = now - boottime.tv_sec;
771 uptime = uptime/3600;
772 /* grab total physical memory */
774 #if defined(HW_PHYSMEM64)
775 mib[1] = HW_PHYSMEM64;
779 len = sizeof(physmem);
780 sysctl(mib, 2, &physmem, &len, NULL, 0);
782 pagesize = getpagesize();
784 while (pagesize > 1) {
789 /* we only need the amount of log(2)1024 for our conversion */
795 len = sizeof(vmtotal);
796 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
797 freeram = (vmtotal.t_free << pageshift);
798 /* generate swap usage and totals */
799 swapmode(&usedswap, &totalswap);
800 freeswap = (totalswap - usedswap);
801 /* grab number of processes */
802 #if defined(__OpenBSD__)
804 mib[1] = KERN_NPROCS;
805 len = sizeof(nprocs);
806 sysctl(mib, 2, &nprocs, &len, NULL, 0);
812 e->command = "core show sysinfo";
814 "Usage: core show sysinfo\n"
815 " List current system information.\n";
821 ast_cli(a->fd, "\nSystem Statistics\n");
822 ast_cli(a->fd, "-----------------\n");
823 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
824 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
825 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
826 #if defined(HAVE_SYSINFO)
827 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
829 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
830 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
831 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
833 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
838 struct profile_entry {
840 uint64_t scale; /* if non-zero, values are scaled by this */
846 struct profile_data {
849 struct profile_entry e[0];
852 static struct profile_data *prof_data;
854 /*! \brief allocates a counter with a given name and scale.
855 * \return Returns the identifier of the counter.
857 int ast_add_profile(const char *name, uint64_t scale)
859 int l = sizeof(struct profile_data);
860 int n = 10; /* default entries */
862 if (prof_data == NULL) {
863 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
864 if (prof_data == NULL)
866 prof_data->entries = 0;
867 prof_data->max_size = n;
869 if (prof_data->entries >= prof_data->max_size) {
871 n = prof_data->max_size + 20;
872 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
876 prof_data->max_size = n;
878 n = prof_data->entries++;
879 prof_data->e[n].name = ast_strdup(name);
880 prof_data->e[n].value = 0;
881 prof_data->e[n].events = 0;
882 prof_data->e[n].mark = 0;
883 prof_data->e[n].scale = scale;
887 int64_t ast_profile(int i, int64_t delta)
889 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
891 if (prof_data->e[i].scale > 1)
892 delta /= prof_data->e[i].scale;
893 prof_data->e[i].value += delta;
894 prof_data->e[i].events++;
895 return prof_data->e[i].value;
898 /* The RDTSC instruction was introduced on the Pentium processor and is not
899 * implemented on certain clones, like the Cyrix 586. Hence, the previous
900 * expectation of __i386__ was in error. */
901 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
902 #if defined(__FreeBSD__)
903 #include <machine/cpufunc.h>
905 static __inline uint64_t
910 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
914 #else /* supply a dummy function on other platforms */
915 static __inline uint64_t
922 int64_t ast_mark(int i, int startstop)
924 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
927 prof_data->e[i].mark = rdtsc();
929 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
930 if (prof_data->e[i].scale > 1)
931 prof_data->e[i].mark /= prof_data->e[i].scale;
932 prof_data->e[i].value += prof_data->e[i].mark;
933 prof_data->e[i].events++;
935 return prof_data->e[i].mark;
938 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
939 max = prof_data->entries;\
940 if (a->argc > 3) { /* specific entries */ \
941 if (isdigit(a->argv[3][0])) { \
942 min = atoi(a->argv[3]); \
943 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
944 max = atoi(a->argv[4]); \
946 search = a->argv[3]; \
948 if (max > prof_data->entries) \
949 max = prof_data->entries;
951 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
954 const char *search = NULL;
957 e->command = "core show profile";
958 e->usage = "Usage: core show profile\n"
959 " show profile information";
965 if (prof_data == NULL)
968 DEFINE_PROFILE_MIN_MAX_VALUES;
969 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
970 prof_data->entries, prof_data->max_size);
971 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
972 "Value", "Average", "Name");
973 for (i = min; i < max; i++) {
974 struct profile_entry *entry = &prof_data->e[i];
975 if (!search || strstr(entry->name, search))
976 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
979 (long)entry->events, (long long)entry->value,
980 (long long)(entry->events ? entry->value / entry->events : entry->value),
986 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
989 const char *search = NULL;
992 e->command = "core clear profile";
993 e->usage = "Usage: core clear profile\n"
994 " clear profile information";
1000 if (prof_data == NULL)
1003 DEFINE_PROFILE_MIN_MAX_VALUES;
1004 for (i= min; i < max; i++) {
1005 if (!search || strstr(prof_data->e[i].name, search)) {
1006 prof_data->e[i].value = 0;
1007 prof_data->e[i].events = 0;
1012 #undef DEFINE_PROFILE_MIN_MAX_VALUES
1014 /*! \brief CLI command to list module versions */
1015 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1017 #define FORMAT "%-25.25s %-40.40s\n"
1018 struct file_version *iterator;
1020 int havepattern = 0;
1022 int count_files = 0;
1024 int matchlen, which = 0;
1025 struct file_version *find;
1029 e->command = "core show file version [like]";
1031 "Usage: core show file version [like <pattern>]\n"
1032 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
1033 " Optional regular expression pattern is used to filter the file list.\n";
1036 matchlen = strlen(a->word);
1039 AST_RWLIST_RDLOCK(&file_versions);
1040 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
1041 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
1042 ret = ast_strdup(find->file);
1046 AST_RWLIST_UNLOCK(&file_versions);
1053 if (!strcasecmp(a->argv[4], "like")) {
1054 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
1055 return CLI_SHOWUSAGE;
1058 return CLI_SHOWUSAGE;
1066 return CLI_SHOWUSAGE;
1069 ast_cli(a->fd, FORMAT, "File", "Revision");
1070 ast_cli(a->fd, FORMAT, "----", "--------");
1071 AST_RWLIST_RDLOCK(&file_versions);
1072 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
1073 if (havename && strcasecmp(iterator->file, a->argv[4]))
1076 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
1079 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
1084 AST_RWLIST_UNLOCK(&file_versions);
1086 ast_cli(a->fd, "%d files listed.\n", count_files);
1096 #endif /* ! LOW_MEMORY */
1098 struct stasis_topic *ast_system_topic(void)
1100 return system_topic;
1103 /*! \brief Cleanup the \ref stasis system level items */
1104 static void stasis_system_topic_cleanup(void)
1106 ao2_cleanup(system_topic);
1107 system_topic = NULL;
1108 STASIS_MESSAGE_TYPE_CLEANUP(ast_network_change_type);
1111 /*! \brief Initialize the system level items for \ref stasis */
1112 static int stasis_system_topic_init(void)
1114 ast_register_atexit(stasis_system_topic_cleanup);
1116 system_topic = stasis_topic_create("ast_system");
1117 if (!system_topic) {
1121 if (STASIS_MESSAGE_TYPE_INIT(ast_network_change_type) != 0) {
1129 * \brief Publish a \ref system_status_type message over \ref stasis
1131 * \param payload The JSON payload to send with the message
1133 static void publish_system_message(const char *message_type, struct ast_json *obj)
1135 RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1136 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
1137 RAII_VAR(struct ast_json *, event_info, NULL, ast_json_unref);
1143 event_info = ast_json_pack("{s: s, s: i, s: o}",
1144 "type", message_type,
1145 "class_type", EVENT_FLAG_SYSTEM,
1151 payload = ast_json_payload_create(event_info);
1156 message = stasis_message_create(ast_manager_get_generic_type(), payload);
1160 stasis_publish(ast_manager_get_topic(), message);
1163 static void publish_fully_booted(void)
1165 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1167 json_object = ast_json_pack("{s: s}",
1168 "Status", "Fully Booted");
1169 publish_system_message("FullyBooted", json_object);
1172 static void ast_run_atexits(void)
1174 struct ast_atexit *ae;
1176 AST_LIST_LOCK(&atexits);
1177 while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1183 AST_LIST_UNLOCK(&atexits);
1186 static void __ast_unregister_atexit(void (*func)(void))
1188 struct ast_atexit *ae;
1190 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1191 if (ae->func == func) {
1192 AST_LIST_REMOVE_CURRENT(list);
1197 AST_LIST_TRAVERSE_SAFE_END;
1200 int ast_register_atexit(void (*func)(void))
1202 struct ast_atexit *ae;
1204 ae = ast_calloc(1, sizeof(*ae));
1210 AST_LIST_LOCK(&atexits);
1211 __ast_unregister_atexit(func);
1212 AST_LIST_INSERT_HEAD(&atexits, ae, list);
1213 AST_LIST_UNLOCK(&atexits);
1218 void ast_unregister_atexit(void (*func)(void))
1220 AST_LIST_LOCK(&atexits);
1221 __ast_unregister_atexit(func);
1222 AST_LIST_UNLOCK(&atexits);
1225 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1226 static int fdsend(int fd, const char *s)
1228 return write(fd, s, strlen(s) + 1);
1231 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1232 static int fdprint(int fd, const char *s)
1234 return write(fd, s, strlen(s));
1237 /*! \brief NULL handler so we can collect the child exit status */
1238 static void _null_sig_handler(int sig)
1242 static struct sigaction null_sig_handler = {
1243 .sa_handler = _null_sig_handler,
1244 .sa_flags = SA_RESTART,
1247 static struct sigaction ignore_sig_handler = {
1248 .sa_handler = SIG_IGN,
1251 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1252 /*! \brief Keep track of how many threads are currently trying to wait*() on
1255 static unsigned int safe_system_level = 0;
1256 static struct sigaction safe_system_prev_handler;
1258 void ast_replace_sigchld(void)
1262 ast_mutex_lock(&safe_system_lock);
1263 level = safe_system_level++;
1265 /* only replace the handler if it has not already been done */
1267 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1270 ast_mutex_unlock(&safe_system_lock);
1273 void ast_unreplace_sigchld(void)
1277 ast_mutex_lock(&safe_system_lock);
1278 level = --safe_system_level;
1280 /* only restore the handler if we are the last one */
1282 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1285 ast_mutex_unlock(&safe_system_lock);
1288 int ast_safe_system(const char *s)
1292 struct rusage rusage;
1295 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1296 ast_replace_sigchld();
1298 #ifdef HAVE_WORKING_FORK
1306 cap_t cap = cap_from_text("cap_net_admin-eip");
1308 if (cap_set_proc(cap)) {
1309 /* Careful with order! Logging cannot happen after we close FDs */
1310 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1314 #ifdef HAVE_WORKING_FORK
1315 if (ast_opt_high_priority)
1316 ast_set_priority(0);
1317 /* Close file descriptors and launch system command */
1318 ast_close_fds_above_n(STDERR_FILENO);
1320 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1322 } else if (pid > 0) {
1324 res = wait4(pid, &status, 0, &rusage);
1326 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1328 } else if (errno != EINTR)
1332 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1336 ast_unreplace_sigchld();
1337 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1345 * \brief enable or disable a logging level to a specified console
1347 void ast_console_toggle_loglevel(int fd, int level, int state)
1351 if (level >= NUMLOGLEVELS) {
1352 level = NUMLOGLEVELS - 1;
1355 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1356 if (fd == consoles[x].fd) {
1358 * Since the logging occurs when levels are false, set to
1359 * flipped iinput because this function accepts 0 as off and 1 as on
1361 consoles[x].levels[level] = state ? 0 : 1;
1368 * \brief mute or unmute a console from logging
1370 void ast_console_toggle_mute(int fd, int silent)
1373 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1374 if (fd == consoles[x].fd) {
1375 if (consoles[x].mute) {
1376 consoles[x].mute = 0;
1378 ast_cli(fd, "Console is not muted anymore.\n");
1380 consoles[x].mute = 1;
1382 ast_cli(fd, "Console is muted.\n");
1387 ast_cli(fd, "Couldn't find remote console.\n");
1391 * \brief log the string to all attached console clients
1393 static void ast_network_puts_mutable(const char *string, int level)
1396 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1397 if (consoles[x].mute)
1399 if (consoles[x].fd > -1) {
1400 if (!consoles[x].levels[level])
1401 fdprint(consoles[x].p[1], string);
1407 * \brief log the string to the console, and all attached
1410 void ast_console_puts_mutable(const char *string, int level)
1412 fputs(string, stdout);
1414 ast_network_puts_mutable(string, level);
1418 * \brief write the string to all attached console clients
1420 static void ast_network_puts(const char *string)
1423 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1424 if (consoles[x].fd > -1)
1425 fdprint(consoles[x].p[1], string);
1430 * \brief write the string to the console, and all attached
1433 void ast_console_puts(const char *string)
1435 fputs(string, stdout);
1437 ast_network_puts(string);
1440 static void network_verboser(const char *s)
1442 ast_network_puts_mutable(s, __LOG_VERBOSE);
1445 static pthread_t lthread;
1448 * \brief read() function supporting the reception of user credentials.
1450 * \param fd Socket file descriptor.
1451 * \param buffer Receive buffer.
1452 * \param size 'buffer' size.
1453 * \param con Console structure to set received credentials
1454 * \retval -1 on error
1455 * \retval the number of bytes received on success.
1457 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1459 #if defined(SO_PEERCRED)
1460 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1461 #define HAVE_STRUCT_UCRED_UID
1462 struct sockpeercred cred;
1466 socklen_t len = sizeof(cred);
1468 #if defined(HAVE_GETPEEREID)
1476 result = read(fd, buffer, size);
1481 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1482 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1485 #if defined(HAVE_STRUCT_UCRED_UID)
1488 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1491 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1493 #elif defined(HAVE_GETPEEREID)
1494 if (getpeereid(fd, &uid, &gid)) {
1506 static void *netconsole(void *vconsole)
1508 struct console *con = vconsole;
1509 char hostname[MAXHOSTNAMELEN] = "";
1512 const char * const end_buf = inbuf + sizeof(inbuf);
1513 char *start_read = inbuf;
1515 struct pollfd fds[2];
1517 if (gethostname(hostname, sizeof(hostname)-1))
1518 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1519 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1520 fdprint(con->fd, outbuf);
1522 fds[0].fd = con->fd;
1523 fds[0].events = POLLIN;
1525 fds[1].fd = con->p[0];
1526 fds[1].events = POLLIN;
1529 res = ast_poll(fds, 2, -1);
1532 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1535 if (fds[0].revents) {
1536 int cmds_read, bytes_read;
1537 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1540 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1541 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1542 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1545 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1546 * NULL and not trailing partial commands. */
1547 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1548 /* No commands were read. We either have a short read on the first command
1549 * with space left, or a command that is too long */
1550 if (start_read + bytes_read < end_buf) {
1551 start_read += bytes_read;
1553 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1558 if (start_read[bytes_read - 1] == '\0') {
1559 /* The read ended on a command boundary, start reading again at the head of inbuf */
1563 /* If we get this far, we have left over characters that have not been processed.
1564 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1565 * We are guaranteed to have at least cmds_read NULLs */
1566 while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1569 memmove(inbuf, start_read, end_buf - start_read);
1570 start_read = end_buf - start_read + inbuf;
1572 if (fds[1].revents) {
1573 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1575 ast_log(LOG_ERROR, "read returned %d\n", res);
1578 res = write(con->fd, outbuf, res);
1583 if (!ast_opt_hide_connect) {
1584 ast_verb(3, "Remote UNIX connection disconnected\n");
1594 static void *listener(void *unused)
1596 struct sockaddr_un sunaddr;
1601 struct pollfd fds[1];
1605 fds[0].fd = ast_socket;
1606 fds[0].events = POLLIN;
1607 s = ast_poll(fds, 1, -1);
1608 pthread_testcancel();
1611 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1614 len = sizeof(sunaddr);
1615 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1618 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1620 #if !defined(SO_PASSCRED)
1624 /* turn on socket credentials passing. */
1625 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1626 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1629 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1630 if (consoles[x].fd >= 0) {
1633 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1634 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1635 consoles[x].fd = -1;
1636 fdprint(s, "Server failed to create pipe\n");
1640 flags = fcntl(consoles[x].p[1], F_GETFL);
1641 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1643 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1644 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1645 to know if the user didn't send the credentials. */
1646 consoles[x].uid = -2;
1647 consoles[x].gid = -2;
1648 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1649 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1650 close(consoles[x].p[0]);
1651 close(consoles[x].p[1]);
1652 consoles[x].fd = -1;
1653 fdprint(s, "Server failed to spawn thread\n");
1658 if (x >= AST_MAX_CONNECTS) {
1659 fdprint(s, "No more connections allowed\n");
1660 ast_log(LOG_WARNING, "No more connections allowed\n");
1662 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1663 ast_verb(3, "Remote UNIX connection\n");
1671 static int ast_makesocket(void)
1673 struct sockaddr_un sunaddr;
1679 for (x = 0; x < AST_MAX_CONNECTS; x++)
1680 consoles[x].fd = -1;
1681 unlink(ast_config_AST_SOCKET);
1682 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1683 if (ast_socket < 0) {
1684 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1687 memset(&sunaddr, 0, sizeof(sunaddr));
1688 sunaddr.sun_family = AF_LOCAL;
1689 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1690 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1692 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1697 res = listen(ast_socket, 2);
1699 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1704 if (ast_register_verbose(network_verboser)) {
1705 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1708 if (ast_pthread_create_background(<hread, NULL, listener, NULL)) {
1709 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1714 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1716 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1717 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1722 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1724 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1725 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1730 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1731 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1733 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1736 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1738 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1739 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1745 static int ast_tryconnect(void)
1747 struct sockaddr_un sunaddr;
1749 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1750 if (ast_consock < 0) {
1751 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1754 memset(&sunaddr, 0, sizeof(sunaddr));
1755 sunaddr.sun_family = AF_LOCAL;
1756 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1757 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1766 /*! \brief Urgent handler
1768 * Called by soft_hangup to interrupt the poll, read, or other
1769 * system call. We don't actually need to do anything though.
1770 * Remember: Cannot EVER ast_log from within a signal handler
1772 static void _urg_handler(int num)
1777 static struct sigaction urg_handler = {
1778 .sa_handler = _urg_handler,
1779 .sa_flags = SA_RESTART,
1782 static void _hup_handler(int num)
1784 int a = 0, save_errno = errno;
1785 printf("Received HUP signal -- Reloading configs\n");
1787 execvp(_argv[0], _argv);
1788 sig_flags.need_reload = 1;
1789 if (sig_alert_pipe[1] != -1) {
1790 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1791 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1797 static struct sigaction hup_handler = {
1798 .sa_handler = _hup_handler,
1799 .sa_flags = SA_RESTART,
1802 static void _child_handler(int sig)
1804 /* Must not ever ast_log or ast_verbose within signal handler */
1805 int n, status, save_errno = errno;
1808 * Reap all dead children -- not just one
1810 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1812 if (n == 0 && option_debug)
1813 printf("Huh? Child handler, but nobody there?\n");
1817 static struct sigaction child_handler = {
1818 .sa_handler = _child_handler,
1819 .sa_flags = SA_RESTART,
1822 /*! \brief Set maximum open files */
1823 static void set_ulimit(int value)
1825 struct rlimit l = {0, 0};
1828 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1835 if (setrlimit(RLIMIT_NOFILE, &l)) {
1836 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1840 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1845 /*! \brief Set an X-term or screen title */
1846 static void set_title(char *text)
1848 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1849 fprintf(stdout, "\033]2;%s\007", text);
1852 static void set_icon(char *text)
1854 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1855 fprintf(stdout, "\033]1;%s\007", text);
1858 /*! \brief We set ourselves to a high priority, that we might pre-empt
1859 * everything else. If your PBX has heavy activity on it, this is a
1862 int ast_set_priority(int pri)
1864 struct sched_param sched;
1865 memset(&sched, 0, sizeof(sched));
1868 sched.sched_priority = 10;
1869 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1870 ast_log(LOG_WARNING, "Unable to set high priority\n");
1873 ast_verb(1, "Set to realtime thread\n");
1875 sched.sched_priority = 0;
1876 /* According to the manpage, these parameters can never fail. */
1877 sched_setscheduler(0, SCHED_OTHER, &sched);
1881 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1882 ast_log(LOG_WARNING, "Unable to set high priority\n");
1885 ast_verb(1, "Set to high priority\n");
1887 /* According to the manpage, these parameters can never fail. */
1888 setpriority(PRIO_PROCESS, 0, 0);
1894 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1895 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1897 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1899 if (can_safely_quit(niceness, restart)) {
1900 really_quit(num, niceness, restart);
1901 /* No one gets here. */
1903 /* It wasn't our time. */
1906 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1908 /* Check if someone else isn't already doing this. */
1909 ast_mutex_lock(&safe_system_lock);
1910 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1911 /* Already in progress and other request was less nice. */
1912 ast_mutex_unlock(&safe_system_lock);
1913 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1916 shuttingdown = niceness;
1917 ast_mutex_unlock(&safe_system_lock);
1919 /* Try to get as many CDRs as possible submitted to the backend engines
1920 * (if in batch mode). really_quit happens to call it again when running
1921 * the atexit handlers, otherwise this would be a bit early. */
1922 ast_cdr_engine_term();
1924 /* Shutdown the message queue for the technology agnostic message channel.
1925 * This has to occur before we pause shutdown pending ast_undestroyed_channels. */
1928 if (niceness == SHUTDOWN_NORMAL) {
1930 /* Begin shutdown routine, hanging up active channels */
1931 ast_begin_shutdown(1);
1932 if (option_verbose && ast_opt_console) {
1933 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1938 /* Wait up to 15 seconds for all channels to go away */
1939 if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1942 /* Sleep 1/10 of a second */
1945 } else if (niceness >= SHUTDOWN_NICE) {
1946 if (niceness != SHUTDOWN_REALLY_NICE) {
1947 ast_begin_shutdown(0);
1949 if (option_verbose && ast_opt_console) {
1950 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1953 if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1960 /* Re-acquire lock and check if someone changed the niceness, in which
1961 * case someone else has taken over the shutdown.
1963 ast_mutex_lock(&safe_system_lock);
1964 if (shuttingdown != niceness) {
1965 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1966 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1968 ast_mutex_unlock(&safe_system_lock);
1971 shuttingdown = SHUTTING_DOWN;
1972 ast_mutex_unlock(&safe_system_lock);
1977 /*! Called when exiting is certain. */
1978 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1980 int active_channels;
1981 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1983 if (niceness >= SHUTDOWN_NICE) {
1984 ast_module_shutdown();
1987 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1988 char filename[80] = "";
1989 if (getenv("HOME")) {
1990 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1992 if (!ast_strlen_zero(filename)) {
1993 ast_el_write_history(filename);
1995 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1996 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
2000 if (el_hist != NULL) {
2001 history_end(el_hist);
2003 } else if (mon_sig_flags == pthread_self()) {
2004 if (consolethread != AST_PTHREADT_NULL) {
2005 pthread_kill(consolethread, SIGURG);
2009 active_channels = ast_active_channels();
2010 json_object = ast_json_pack("{s: s, s: s}",
2011 "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
2012 "Restart", restart ? "True" : "False");
2013 publish_system_message("Shutdown", json_object);
2014 ast_verb(0, "Asterisk %s ending (%d).\n",
2015 active_channels ? "uncleanly" : "cleanly", num);
2017 ast_verb(0, "Executing last minute cleanups\n");
2020 ast_debug(1, "Asterisk ending (%d).\n", num);
2021 if (ast_socket > -1) {
2022 pthread_cancel(lthread);
2025 unlink(ast_config_AST_SOCKET);
2027 if (ast_consock > -1)
2029 if (!ast_opt_remote)
2030 unlink(ast_config_AST_PID);
2031 printf("%s", term_quit());
2034 ast_verb(0, "Preparing for Asterisk restart...\n");
2035 /* Mark all FD's for closing on exec */
2036 for (i = 3; i < 32768; i++) {
2037 fcntl(i, F_SETFD, FD_CLOEXEC);
2039 ast_verb(0, "Asterisk is now restarting...\n");
2046 /* If there is a consolethread running send it a SIGHUP
2047 so it can execvp, otherwise we can do it ourselves */
2048 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
2049 pthread_kill(consolethread, SIGHUP);
2050 /* Give the signal handler some time to complete */
2053 execvp(_argv[0], _argv);
2064 static void __quit_handler(int num)
2067 sig_flags.need_quit = 1;
2068 if (sig_alert_pipe[1] != -1) {
2069 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
2070 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
2073 /* There is no need to restore the signal handler here, since the app
2074 * is going to exit */
2077 static void __remote_quit_handler(int num)
2079 sig_flags.need_quit = 1;
2082 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
2086 if (!strncmp(s, cmp, strlen(cmp))) {
2087 c = s + strlen(cmp);
2088 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
2094 /* These gymnastics are due to platforms which designate char as unsigned by
2095 * default. Level is the negative character -- offset by 1, because \0 is the
2097 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
2098 #define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
2100 static void console_verboser(const char *s)
2103 const char *c = NULL;
2106 if (VERBOSE_HASMAGIC(s)) {
2107 level = VERBOSE_MAGIC2LEVEL(s);
2109 if (level > option_verbose) {
2114 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
2115 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
2116 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
2117 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
2126 /* Wake up a poll()ing console */
2127 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2128 pthread_kill(consolethread, SIGURG);
2132 static int ast_all_zeros(char *s)
2142 static void consolehandler(char *s)
2144 printf("%s", term_end());
2147 /* Called when readline data is available */
2148 if (!ast_all_zeros(s))
2149 ast_el_add_history(s);
2150 /* The real handler for bang */
2153 ast_safe_system(s+1);
2155 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2157 ast_cli_command(STDOUT_FILENO, s);
2160 static int remoteconsolehandler(char *s)
2164 /* Called when readline data is available */
2165 if (!ast_all_zeros(s))
2166 ast_el_add_history(s);
2167 /* The real handler for bang */
2170 ast_safe_system(s+1);
2172 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2174 } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2175 int old_verbose = option_verbose;
2176 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2178 if (sscanf(s + 25, "%d", &tmp) != 1) {
2179 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2181 if (tmp > option_verbose) {
2182 option_verbose = tmp;
2184 if (old_verbose != option_verbose) {
2185 fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2187 fprintf(stdout, "Verbosity level unchanged.\n");
2191 if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2192 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2194 if (old_verbose != option_verbose) {
2195 fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2197 fprintf(stdout, "Verbosity level unchanged.\n");
2202 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2203 (s[4] == '\0' || isspace(s[4]))) {
2204 quit_handler(0, SHUTDOWN_FAST, 0);
2211 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2215 e->command = "core show version";
2217 "Usage: core show version\n"
2218 " Shows Asterisk version information.\n";
2225 return CLI_SHOWUSAGE;
2226 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2227 ast_get_version(), ast_build_user, ast_build_hostname,
2228 ast_build_machine, ast_build_os, ast_build_date);
2233 static int handle_quit(int fd, int argc, char *argv[])
2236 return RESULT_SHOWUSAGE;
2237 quit_handler(0, SHUTDOWN_NORMAL, 0);
2238 return RESULT_SUCCESS;
2242 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2246 e->command = "core stop now";
2248 "Usage: core stop now\n"
2249 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2255 if (a->argc != e->args)
2256 return CLI_SHOWUSAGE;
2257 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2261 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2265 e->command = "core stop gracefully";
2267 "Usage: core stop gracefully\n"
2268 " Causes Asterisk to not accept new calls, and exit when all\n"
2269 " active calls have terminated normally.\n";
2275 if (a->argc != e->args)
2276 return CLI_SHOWUSAGE;
2277 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2281 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2285 e->command = "core stop when convenient";
2287 "Usage: core stop when convenient\n"
2288 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2294 if (a->argc != e->args)
2295 return CLI_SHOWUSAGE;
2296 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2297 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2301 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2305 e->command = "core restart now";
2307 "Usage: core restart now\n"
2308 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2315 if (a->argc != e->args)
2316 return CLI_SHOWUSAGE;
2317 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2321 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2325 e->command = "core restart gracefully";
2327 "Usage: core restart gracefully\n"
2328 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2329 " restart when all active calls have ended.\n";
2335 if (a->argc != e->args)
2336 return CLI_SHOWUSAGE;
2337 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2341 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2345 e->command = "core restart when convenient";
2347 "Usage: core restart when convenient\n"
2348 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2354 if (a->argc != e->args)
2355 return CLI_SHOWUSAGE;
2356 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2357 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2361 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2363 int aborting_shutdown = 0;
2367 e->command = "core abort shutdown";
2369 "Usage: core abort shutdown\n"
2370 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2371 " call operations.\n";
2377 if (a->argc != e->args)
2378 return CLI_SHOWUSAGE;
2380 ast_mutex_lock(&safe_system_lock);
2381 if (shuttingdown >= SHUTDOWN_FAST) {
2382 aborting_shutdown = 1;
2383 shuttingdown = NOT_SHUTTING_DOWN;
2385 ast_mutex_unlock(&safe_system_lock);
2387 if (aborting_shutdown) {
2388 ast_cancel_shutdown();
2393 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2399 "Usage: !<command>\n"
2400 " Executes a given shell command\n";
2408 static const char warranty_lines[] = {
2412 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2413 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2414 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2415 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2416 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2417 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2418 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2419 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2420 "REPAIR OR CORRECTION.\n"
2422 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2423 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2424 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2425 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2426 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2427 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2428 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2429 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2430 "POSSIBILITY OF SUCH DAMAGES.\n"
2433 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2437 e->command = "core show warranty";
2439 "Usage: core show warranty\n"
2440 " Shows the warranty (if any) for this copy of Asterisk.\n";
2446 ast_cli(a->fd, "%s", warranty_lines);
2451 static const char license_lines[] = {
2453 "This program is free software; you can redistribute it and/or modify\n"
2454 "it under the terms of the GNU General Public License version 2 as\n"
2455 "published by the Free Software Foundation.\n"
2457 "This program also contains components licensed under other licenses.\n"
2460 "This program is distributed in the hope that it will be useful,\n"
2461 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2462 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2463 "GNU General Public License for more details.\n"
2465 "You should have received a copy of the GNU General Public License\n"
2466 "along with this program; if not, write to the Free Software\n"
2467 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2470 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2474 e->command = "core show license";
2476 "Usage: core show license\n"
2477 " Shows the license(s) for this copy of Asterisk.\n";
2483 ast_cli(a->fd, "%s", license_lines);
2488 #define ASTERISK_PROMPT "*CLI> "
2490 #define ASTERISK_PROMPT2 "%s*CLI> "
2493 * \brief Shutdown Asterisk CLI commands.
2495 * \note These CLI commands cannot be unregistered at shutdown
2496 * because one of them is likely the reason for the shutdown.
2497 * The CLI generates a warning if a command is in-use when it is
2500 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2501 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2502 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2503 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2504 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2505 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2506 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2509 static struct ast_cli_entry cli_asterisk[] = {
2510 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2511 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2512 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2513 AST_CLI_DEFINE(handle_version, "Display version info"),
2514 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2515 #if !defined(LOW_MEMORY)
2516 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2517 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2518 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2519 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2521 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2522 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2523 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2524 #endif /* ! LOW_MEMORY */
2527 struct el_read_char_state_struct {
2528 unsigned int line_full:1;
2529 unsigned int prev_line_full:1;
2530 char prev_line_verbosity;
2533 static int el_read_char_state_init(void *ptr)
2535 struct el_read_char_state_struct *state = ptr;
2536 state->line_full = 1;
2537 state->prev_line_full = 1;
2538 state->prev_line_verbosity = 0;
2542 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2544 static int ast_el_read_char(EditLine *editline, char *cp)
2548 struct pollfd fds[2];
2551 #define EL_BUF_SIZE 512
2552 char buf[EL_BUF_SIZE];
2553 struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2557 fds[0].fd = ast_consock;
2558 fds[0].events = POLLIN;
2559 if (!ast_opt_exec) {
2560 fds[1].fd = STDIN_FILENO;
2561 fds[1].events = POLLIN;
2564 res = ast_poll(fds, max, -1);
2566 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2570 fprintf(stderr, "poll failed: %s\n", strerror(errno));
2574 if (!ast_opt_exec && fds[1].revents) {
2575 num_read = read(STDIN_FILENO, cp, 1);
2582 if (fds[0].revents) {
2584 char *curline = buf, *nextline;
2585 res = read(ast_consock, buf, sizeof(buf) - 1);
2586 /* if the remote side disappears exit */
2588 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2589 if (!ast_opt_reconnect) {
2590 quit_handler(0, SHUTDOWN_FAST, 0);
2593 int reconnects_per_second = 20;
2594 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2595 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2596 if (ast_tryconnect()) {
2597 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2598 printf("%s", term_quit());
2601 fdsend(ast_consock, "logger mute silent");
2603 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2606 usleep(1000000 / reconnects_per_second);
2608 if (tries >= 30 * reconnects_per_second) {
2609 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2610 quit_handler(0, SHUTDOWN_FAST, 0);
2618 /* Write over the CLI prompt */
2619 if (!ast_opt_exec && !lastpos) {
2620 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2625 state->prev_line_full = state->line_full;
2626 if ((nextline = strchr(curline, '\n'))) {
2627 state->line_full = 1;
2630 state->line_full = 0;
2631 nextline = strchr(curline, '\0');
2634 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2635 level = VERBOSE_MAGIC2LEVEL(curline);
2637 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2638 /* Non-verbose output */
2641 level = state->prev_line_verbosity;
2643 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2644 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2648 state->prev_line_verbosity = level;
2650 } while (!ast_strlen_zero(curline));
2652 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2664 static struct ast_str *prompt = NULL;
2666 static char *cli_prompt(EditLine *editline)
2671 static int cli_prompt_changes = 0;
2675 if (prompt == NULL) {
2676 prompt = ast_str_create(100);
2677 } else if (!cli_prompt_changes) {
2678 return ast_str_buffer(prompt);
2680 ast_str_reset(prompt);
2683 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2685 struct timeval ts = ast_tvnow();
2686 while (*t != '\0') {
2688 char hostname[MAXHOSTNAMELEN] = "";
2690 struct ast_tm tm = { 0, };
2691 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2695 case 'C': /* color */
2697 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2698 ast_term_color_code(&prompt, fgcolor, bgcolor);
2700 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2701 ast_term_color_code(&prompt, fgcolor, 0);
2705 /* If the color has been reset correctly, then there's no need to reset it later */
2706 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2708 case 'd': /* date */
2709 if (ast_localtime(&ts, &tm, NULL)) {
2710 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2711 ast_str_append(&prompt, 0, "%s", tmp);
2712 cli_prompt_changes++;
2715 case 'g': /* group */
2716 if ((gr = getgrgid(getgid()))) {
2717 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2720 case 'h': /* hostname */
2721 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2722 ast_str_append(&prompt, 0, "%s", hostname);
2724 ast_str_append(&prompt, 0, "%s", "localhost");
2727 case 'H': /* short hostname */
2728 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2730 if ((dotptr = strchr(hostname, '.'))) {
2733 ast_str_append(&prompt, 0, "%s", hostname);
2735 ast_str_append(&prompt, 0, "%s", "localhost");
2738 #ifdef HAVE_GETLOADAVG
2739 case 'l': /* load avg */
2741 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2743 getloadavg(list, 3);
2744 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2745 cli_prompt_changes++;
2749 case 's': /* Asterisk system name (from asterisk.conf) */
2750 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2752 case 't': /* time */
2753 if (ast_localtime(&ts, &tm, NULL)) {
2754 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2755 ast_str_append(&prompt, 0, "%s", tmp);
2756 cli_prompt_changes++;
2759 case 'u': /* username */
2760 if ((pw = getpwuid(getuid()))) {
2761 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2764 case '#': /* process console or remote? */
2765 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2767 case '%': /* literal % */
2768 ast_str_append(&prompt, 0, "%c", '%');
2770 case '\0': /* % is last character - prevent bug */
2775 ast_str_append(&prompt, 0, "%c", *t);
2780 /* Force colors back to normal at end */
2781 ast_term_color_code(&prompt, 0, 0);
2783 } else if (remotehostname) {
2784 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2786 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2789 return ast_str_buffer(prompt);
2792 static char **ast_el_strtoarr(char *buf)
2794 char **match_list = NULL, **match_list_tmp, *retstr;
2795 size_t match_list_len;
2799 while ( (retstr = strsep(&buf, " ")) != NULL) {
2801 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2803 if (matches + 1 >= match_list_len) {
2804 match_list_len <<= 1;
2805 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2806 match_list = match_list_tmp;
2809 ast_free(match_list);
2810 return (char **) NULL;
2814 match_list[matches++] = ast_strdup(retstr);
2818 return (char **) NULL;
2820 if (matches >= match_list_len) {
2821 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2822 match_list = match_list_tmp;
2825 ast_free(match_list);
2826 return (char **) NULL;
2830 match_list[matches] = (char *) NULL;
2835 static int ast_el_sort_compare(const void *i1, const void *i2)
2839 s1 = ((char **)i1)[0];
2840 s2 = ((char **)i2)[0];
2842 return strcasecmp(s1, s2);
2845 static int ast_cli_display_match_list(char **matches, int len, int max)
2847 int i, idx, limit, count;
2848 int screenwidth = 0;
2849 int numoutput = 0, numoutputline = 0;
2851 screenwidth = ast_get_termcols(STDOUT_FILENO);
2853 /* find out how many entries can be put on one line, with two spaces between strings */
2854 limit = screenwidth / (max + 2);
2858 /* how many lines of output */
2859 count = len / limit;
2860 if (count * limit < len)
2865 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2867 for (; count > 0; count--) {
2869 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2871 /* Don't print dupes */
2872 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2874 ast_free(matches[idx]);
2875 matches[idx] = NULL;
2881 fprintf(stdout, "%-*s ", max, matches[idx]);
2882 ast_free(matches[idx]);
2883 matches[idx] = NULL;
2885 if (numoutputline > 0)
2886 fprintf(stdout, "\n");
2893 static char *cli_complete(EditLine *editline, int ch)
2899 int retval = CC_ERROR;
2900 char buf[2048], savechr;
2903 LineInfo *lf = (LineInfo *)el_line(editline);
2905 savechr = *(char *)lf->cursor;
2906 *(char *)lf->cursor = '\0';
2907 ptr = (char *)lf->cursor;
2909 while (ptr > lf->buffer) {
2910 if (isspace(*ptr)) {
2918 len = lf->cursor - ptr;
2920 if (ast_opt_remote) {
2921 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2922 fdsend(ast_consock, buf);
2923 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2924 return (char*)(CC_ERROR);
2927 nummatches = atoi(buf);
2929 if (nummatches > 0) {
2931 int mlen = 0, maxmbuf = 2048;
2932 /* Start with a 2048 byte buffer */
2933 if (!(mbuf = ast_malloc(maxmbuf))) {
2934 *((char *) lf->cursor) = savechr;
2935 return (char *)(CC_ERROR);
2937 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2938 fdsend(ast_consock, buf);
2941 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2942 if (mlen + 1024 > maxmbuf) {
2943 /* Every step increment buffer 1024 bytes */
2945 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2946 *((char *) lf->cursor) = savechr;
2947 return (char *)(CC_ERROR);
2950 /* Only read 1024 bytes at a time */
2951 res = read(ast_consock, mbuf + mlen, 1024);
2957 matches = ast_el_strtoarr(mbuf);
2960 matches = (char **) NULL;
2962 char **p, *oldbuf=NULL;
2964 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2965 for (p = matches; p && *p; p++) {
2966 if (!oldbuf || strcmp(*p,oldbuf))
2974 int matches_num, maxlen, match_len;
2976 if (matches[0][0] != '\0') {
2977 el_deletestr(editline, (int) len);
2978 el_insertstr(editline, matches[0]);
2979 retval = CC_REFRESH;
2982 if (nummatches == 1) {
2983 /* Found an exact match */
2984 el_insertstr(editline, " ");
2985 retval = CC_REFRESH;
2987 /* Must be more than one match */
2988 for (i = 1, maxlen = 0; matches[i]; i++) {
2989 match_len = strlen(matches[i]);
2990 if (match_len > maxlen)
2993 matches_num = i - 1;
2994 if (matches_num >1) {
2995 fprintf(stdout, "\n");
2996 ast_cli_display_match_list(matches, nummatches, maxlen);
2997 retval = CC_REDISPLAY;
2999 el_insertstr(editline," ");
3000 retval = CC_REFRESH;
3003 for (i = 0; matches[i]; i++)
3004 ast_free(matches[i]);
3008 *((char *) lf->cursor) = savechr;
3010 return (char *)(long)retval;
3013 static int ast_el_initialize(void)
3016 char *editor, *editrc = getenv("EDITRC");
3018 if (!(editor = getenv("AST_EDITMODE"))) {
3019 if (!(editor = getenv("AST_EDITOR"))) {
3026 if (el_hist != NULL)
3027 history_end(el_hist);
3029 el = el_init("asterisk", stdin, stdout, stderr);
3030 el_set(el, EL_PROMPT, cli_prompt);
3032 el_set(el, EL_EDITMODE, 1);
3033 el_set(el, EL_EDITOR, editor);
3034 el_hist = history_init();
3035 if (!el || !el_hist)
3038 /* setup history with 100 entries */
3039 history(el_hist, &ev, H_SETSIZE, 100);
3041 el_set(el, EL_HIST, history, el_hist);
3043 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
3044 /* Bind <tab> to command completion */
3045 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
3046 /* Bind ? to command completion */
3047 el_set(el, EL_BIND, "?", "ed-complete", NULL);
3048 /* Bind ^D to redisplay */
3049 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
3050 /* Bind Delete to delete char left */
3051 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
3052 /* Bind Home and End to move to line start and end */
3053 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3054 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3055 /* Bind C-left and C-right to move by word (not all terminals) */
3056 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
3057 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
3060 el_source(el, editrc);
3066 #define MAX_HISTORY_COMMAND_LENGTH 256
3068 static int ast_el_add_history(char *buf)
3072 if (el_hist == NULL || el == NULL)
3073 ast_el_initialize();
3074 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
3076 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
3079 static int ast_el_write_history(char *filename)
3083 if (el_hist == NULL || el == NULL)
3084 ast_el_initialize();
3086 return (history(el_hist, &ev, H_SAVE, filename));
3089 static int ast_el_read_history(char *filename)
3093 if (el_hist == NULL || el == NULL) {
3094 ast_el_initialize();
3097 return history(el_hist, &ev, H_LOAD, filename);
3100 static void ast_remotecontrol(char *data)
3104 char filename[80] = "";
3109 char *stringp = NULL;
3114 memset(&sig_flags, 0, sizeof(sig_flags));
3115 signal(SIGINT, __remote_quit_handler);
3116 signal(SIGTERM, __remote_quit_handler);
3117 signal(SIGHUP, __remote_quit_handler);
3119 if (read(ast_consock, buf, sizeof(buf)) < 0) {
3120 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3124 char prefix[] = "cli quit after ";
3125 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3126 sprintf(tmp, "%s%s", prefix, data);
3127 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3128 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3129 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3135 hostname = strsep(&stringp, "/");
3136 cpid = strsep(&stringp, "/");
3137 version = strsep(&stringp, "\n");
3139 version = "<Version Unknown>";
3141 strsep(&stringp, ".");
3147 if (!ast_opt_mute) {
3148 fdsend(ast_consock, "logger mute silent");
3150 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3154 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
3155 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3157 fds.fd = ast_consock;
3158 fds.events = POLLIN;
3161 while (ast_poll(&fds, 1, 60000) > 0) {
3162 char buffer[512] = "", *curline = buffer, *nextline;
3163 int not_written = 1;
3165 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3169 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3174 prev_linefull = linefull;
3175 if ((nextline = strchr(curline, '\n'))) {
3180 nextline = strchr(curline, '\0');
3183 /* Skip verbose lines */
3184 /* Prev line full? | Line is verbose | Last line verbose? | Print
3185 * TRUE | TRUE* | TRUE | FALSE
3186 * TRUE | TRUE* | FALSE | FALSE
3187 * TRUE | FALSE* | TRUE | TRUE
3188 * TRUE | FALSE* | FALSE | TRUE
3189 * FALSE | TRUE | TRUE* | FALSE
3190 * FALSE | TRUE | FALSE* | TRUE
3191 * FALSE | FALSE | TRUE* | FALSE
3192 * FALSE | FALSE | FALSE* | TRUE
3194 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3195 prev_line_verbose = 0;
3197 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3198 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3201 prev_line_verbose = 1;
3204 } while (!ast_strlen_zero(curline));
3206 /* No non-verbose output in 60 seconds. */
3214 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3215 remotehostname = hostname;
3217 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3218 if (el_hist == NULL || el == NULL)
3219 ast_el_initialize();
3221 el_set(el, EL_GETCFN, ast_el_read_char);
3223 if (!ast_strlen_zero(filename))
3224 ast_el_read_history(filename);
3227 ebuf = (char *)el_gets(el, &num);
3229 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3233 if (!ebuf && write(1, "", 1) < 0)
3236 if (!ast_strlen_zero(ebuf)) {
3237 if (ebuf[strlen(ebuf)-1] == '\n')
3238 ebuf[strlen(ebuf)-1] = '\0';
3239 if (!remoteconsolehandler(ebuf)) {
3240 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3242 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3248 printf("\nDisconnected from Asterisk server\n");
3251 static int show_version(void)
3253 printf("Asterisk %s\n", ast_get_version());
3257 static int show_cli_help(void)
3259 printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3260 printf("Usage: asterisk [OPTIONS]\n");
3261 printf("Valid Options:\n");
3262 printf(" -V Display version number and exit\n");
3263 printf(" -C <configfile> Use an alternate configuration file\n");
3264 printf(" -G <group> Run as a group other than the caller\n");
3265 printf(" -U <user> Run as a user other than the caller\n");
3266 printf(" -c Provide console CLI\n");
3267 printf(" -d Enable extra debugging\n");
3268 #if HAVE_WORKING_FORK
3269 printf(" -f Do not fork\n");
3270 printf(" -F Always fork\n");
3272 printf(" -g Dump core in case of a crash\n");
3273 printf(" -h This help screen\n");
3274 printf(" -i Initialize crypto keys at startup\n");
3275 printf(" -I Enable internal timing if DAHDI timer is available\n");
3276 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
3277 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
3278 printf(" -m Mute debugging and console output on the console\n");
3279 printf(" -n Disable console colorization\n");
3280 printf(" -p Run as pseudo-realtime thread\n");
3281 printf(" -q Quiet mode (suppress output)\n");
3282 printf(" -r Connect to Asterisk on this machine\n");
3283 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
3284 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
3285 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
3286 printf(" belong after they are done\n");
3287 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3288 printf(" of output to the CLI\n");
3289 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
3290 printf(" -x <cmd> Execute command <cmd> (implies -r)\n");
3291 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
3292 printf(" -W Adjust terminal colors to compensate for a light background\n");
3297 static void ast_readconfig(void)
3299 struct ast_config *cfg;
3300 struct ast_variable *v;
3301 char *config = DEFAULT_CONFIG_FILE;
3302 char hostname[MAXHOSTNAMELEN] = "";
3303 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3305 unsigned int dbdir:1;
3306 unsigned int keydir:1;
3309 /* Set default value */
3310 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3312 if (ast_opt_override_config) {
3313 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3314 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3315 fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3318 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3321 /* init with buildtime config */
3322 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3323 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3324 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3325 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3326 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3327 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3328 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3329 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3330 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3331 ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3332 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3333 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3334 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3335 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3337 ast_set_default_eid(&ast_eid_default);
3339 /* no asterisk.conf? no problem, use buildtime config! */
3340 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3344 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3345 if (!strcasecmp(v->name, "astctlpermissions"))
3346 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3347 else if (!strcasecmp(v->name, "astctlowner"))
3348 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3349 else if (!strcasecmp(v->name, "astctlgroup"))
3350 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3351 else if (!strcasecmp(v->name, "astctl"))
3352 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3355 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3356 if (!strcasecmp(v->name, "astetcdir")) {
3357 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3358 } else if (!strcasecmp(v->name, "astspooldir")) {
3359 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3360 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3361 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3362 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3364 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3365 } else if (!strcasecmp(v->name, "astdbdir")) {
3366 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3368 } else if (!strcasecmp(v->name, "astdatadir")) {
3369 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3371 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3372 } else if (!strcasecmp(v->name, "astkeydir")) {
3373 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3375 } else if (!strcasecmp(v->name, "astlogdir")) {
3376 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3377 } else if (!strcasecmp(v->name, "astagidir")) {
3378 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3379 } else if (!strcasecmp(v->name, "astrundir")) {
3380 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3381 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3382 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3383 } else if (!strcasecmp(v->name, "astmoddir")) {
3384 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3385 } else if (!strcasecmp(v->name, "astsbindir")) {
3386 ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3390 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3391 /* verbose level (-v at startup) */
3392 if (!strcasecmp(v->name, "verbose")) {
3393 option_verbose = atoi(v->value);
3394 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3395 } else if (!strcasecmp(v->name, "timestamp")) {
3396 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3397 /* whether or not to support #exec in config files */
3398 } else if (!strcasecmp(v->name, "execincludes")) {
3399 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3400 /* debug level (-d at startup) */
3401 } else if (!strcasecmp(v->name, "debug")) {
3403 if (sscanf(v->value, "%30d", &option_debug) != 1) {
3404 option_debug = ast_true(v->value);
3406 #if HAVE_WORKING_FORK
3407 /* Disable forking (-f at startup) */
3408 } else if (!strcasecmp(v->name, "nofork")) {
3409 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3410 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3411 } else if (!strcasecmp(v->name, "alwaysfork")) {
3412 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3414 /* Run quietly (-q at startup ) */
3415 } else if (!strcasecmp(v->name, "quiet")) {
3416 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3417 /* Run as console (-c at startup, implies nofork) */
3418 } else if (!strcasecmp(v->name, "console")) {
3419 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3420 /* Run with high priority if the O/S permits (-p at startup) */
3421 } else if (!strcasecmp(v->name, "highpriority")) {
3422 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3423 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3424 } else if (!strcasecmp(v->name, "initcrypto")) {
3425 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3426 /* Disable ANSI colors for console (-c at startup) */
3427 } else if (!strcasecmp(v->name, "nocolor")) {
3428 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3429 /* Disable some usage warnings for picky people :p */
3430 } else if (!strcasecmp(v->name, "dontwarn")) {
3431 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3432 /* Dump core in case of crash (-g) */
3433 } else if (!strcasecmp(v->name, "dumpcore")) {
3434 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3435 /* Cache recorded sound files to another directory during recording */
3436 } else if (!strcasecmp(v->name, "cache_record_files")) {
3437 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3438 /* Specify cache directory */
3439 } else if (!strcasecmp(v->name, "record_cache_dir")) {
3440 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3441 /* Build transcode paths via SLINEAR, instead of directly */
3442 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3443 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3444 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3445 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3446 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3447 /* Enable internal timing */
3448 } else if (!strcasecmp(v->name, "internal_timing")) {
3449 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
3450 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3451 if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3452 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3454 } else if (!strcasecmp(v->name, "maxcalls")) {
3455 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3456 option_maxcalls = 0;
3458 } else if (!strcasecmp(v->name, "maxload")) {
3461 if (getloadavg(test, 1) == -1) {
3462 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3463 option_maxload = 0.0;
3464 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3465 option_maxload = 0.0;
3467 /* Set the maximum amount of open files */
3468 } else if (!strcasecmp(v->name, "maxfiles")) {
3469 option_maxfiles = atoi(v->value);
3470 set_ulimit(option_maxfiles);
3471 /* What user to run as */
3472 } else if (!strcasecmp(v->name, "runuser")) {
3473 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3474 /* What group to run as */
3475 } else if (!strcasecmp(v->name, "rungroup")) {
3476 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3477 } else if (!strcasecmp(v->name, "systemname")) {
3478 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3479 } else if (!strcasecmp(v->name, "autosystemname")) {
3480 if (ast_true(v->value)) {
3481 if (!gethostname(hostname, sizeof(hostname) - 1))
3482 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3484 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3485 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3487 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3490 } else if (!strcasecmp(v->name, "languageprefix")) {
3491 ast_language_is_prefix = ast_true(v->value);
3492 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3493 ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
3494 } else if (!strcasecmp(v->name, "lockmode")) {
3495 if (!strcasecmp(v->value, "lockfile")) {
3496 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3497 } else if (!strcasecmp(v->value, "flock")) {
3498 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3500 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3501 "defaulting to 'lockfile'\n", v->value);
3502 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3504 #if defined(HAVE_SYSINFO)
3505 } else if (!strcasecmp(v->name, "minmemfree")) {
3506 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
3507 * if the amount of free memory falls below this watermark */
3508 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3509 option_minmemfree = 0;
3512 } else if (!strcasecmp(v->name, "entityid")) {
3513 struct ast_eid tmp_eid;
3514 if (!ast_str_to_eid(&tmp_eid, v->value)) {
3515 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3516 ast_eid_default = tmp_eid;
3518 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3519 } else if (!strcasecmp(v->name, "lightbackground")) {
3520 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3521 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3522 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3523 } else if (!strcasecmp(v->name, "hideconnect")) {
3524 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3525 } else if (!strcasecmp(v->name, "lockconfdir")) {
3526 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3527 } else if (!strcasecmp(v->name, "stdexten")) {
3528 /* Choose how to invoke the extensions.conf stdexten */
3529 if (!strcasecmp(v->value, "gosub")) {
3530 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3531 } else if (!strcasecmp(v->value, "macro")) {
3532 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3534 ast_log(LOG_WARNING,
3535 "'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
3537 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3541 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3543 if (sscanf(v->value, "%30f", &version) != 1) {
3544 fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3547 if (!strcasecmp(v->name, "app_set")) {
3548 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3549 } else if (!strcasecmp(v->name, "res_agi")) {
3550 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3551 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3552 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3555 ast_config_destroy(cfg);
3558 static void *monitor_sig_flags(void *unused)
3561 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3563 ast_poll(&p, 1, -1);
3564 if (sig_flags.need_reload) {
3565 sig_flags.need_reload = 0;
3566 ast_module_reload(NULL);
3568 if (sig_flags.need_quit) {
3569 sig_flags.need_quit = 0;
3570 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3571 sig_flags.need_quit_handler = 1;
3572 pthread_kill(consolethread, SIGURG);
3574 quit_handler(0, SHUTDOWN_NORMAL, 0);
3577 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3584 static void *canary_thread(void *unused)
3586 struct stat canary_stat;
3589 /* Give the canary time to sing */
3594 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3595 ast_log(LOG_WARNING,
3596 "The canary is no more. He has ceased to be! "
3597 "He's expired and gone to meet his maker! "
3598 "He's a stiff! Bereft of life, he rests in peace. "
3599 "His metabolic processes are now history! He's off the twig! "
3600 "He's kicked the bucket. He's shuffled off his mortal coil, "
3601 "run down the curtain, and joined the bleeding choir invisible!! "
3602 "THIS is an EX-CANARY. (Reducing priority)\n");
3603 ast_set_priority(0);