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 */
351 AST_LIST_ENTRY(ast_atexit) list;
354 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
356 struct timeval ast_startuptime;
357 struct timeval ast_lastreloadtime;
359 static History *el_hist;
361 static char *remotehostname;
363 struct console consoles[AST_MAX_CONNECTS];
365 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
367 static int ast_el_add_history(char *);
368 static int ast_el_read_history(char *);
369 static int ast_el_write_history(char *);
372 char config_dir[PATH_MAX];
373 char module_dir[PATH_MAX];
374 char spool_dir[PATH_MAX];
375 char monitor_dir[PATH_MAX];
376 char var_dir[PATH_MAX];
377 char data_dir[PATH_MAX];
378 char log_dir[PATH_MAX];
379 char agi_dir[PATH_MAX];
380 char run_dir[PATH_MAX];
381 char key_dir[PATH_MAX];
383 char config_file[PATH_MAX];
384 char db_path[PATH_MAX];
385 char sbin_dir[PATH_MAX];
386 char pid_path[PATH_MAX];
387 char socket_path[PATH_MAX];
388 char run_user[PATH_MAX];
389 char run_group[PATH_MAX];
390 char system_name[128];
393 static struct _cfg_paths cfg_paths;
395 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
396 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
397 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
398 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
399 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
400 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
401 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
402 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
403 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
404 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
405 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
406 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
408 const char *ast_config_AST_DB = cfg_paths.db_path;
409 const char *ast_config_AST_PID = cfg_paths.pid_path;
410 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
411 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
412 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
413 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
415 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
416 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
417 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
418 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
420 extern unsigned int ast_FD_SETSIZE;
422 static char *_argv[256];
424 NOT_SHUTTING_DOWN = -2,
426 /* Valid values for quit_handler niceness below: */
432 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
433 static int restartnow;
434 static pthread_t consolethread = AST_PTHREADT_NULL;
435 static pthread_t mon_sig_flags;
436 static int canary_pid = 0;
437 static char canary_filename[128];
438 static int multi_thread_safe;
440 static char randompool[256];
442 static int sig_alert_pipe[2] = { -1, -1 };
444 unsigned int need_reload:1;
445 unsigned int need_quit:1;
446 unsigned int need_quit_handler:1;
449 /*! \brief The \ref stasis topic for system level changes */
450 static struct stasis_topic *system_topic;
452 /*!\ brief The \ref stasis_message_type for network changes */
453 STASIS_MESSAGE_TYPE_DEFN(ast_network_change_type);
455 #if !defined(LOW_MEMORY)
456 struct file_version {
457 AST_RWLIST_ENTRY(file_version) list;
462 /*! \brief The \ref stasis topic for system level changes */
463 static struct stasis_topic *system_topic;
465 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
467 void ast_register_file_version(const char *file, const char *version)
469 struct file_version *new;
471 size_t version_length;
473 work = ast_strdupa(version);
474 work = ast_strip(ast_strip_quoted(work, "$", "$"));
475 version_length = strlen(work) + 1;
477 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
481 new->version = (char *) new + sizeof(*new);
482 memcpy(new->version, work, version_length);
483 AST_RWLIST_WRLOCK(&file_versions);
484 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
485 AST_RWLIST_UNLOCK(&file_versions);
488 void ast_unregister_file_version(const char *file)
490 struct file_version *find;
492 AST_RWLIST_WRLOCK(&file_versions);
493 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
494 if (!strcasecmp(find->file, file)) {
495 AST_RWLIST_REMOVE_CURRENT(list);
499 AST_RWLIST_TRAVERSE_SAFE_END;
500 AST_RWLIST_UNLOCK(&file_versions);
506 char *ast_complete_source_filename(const char *partial, int n)
508 struct file_version *find;
509 size_t len = strlen(partial);
513 AST_RWLIST_RDLOCK(&file_versions);
514 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
515 if (!strncasecmp(find->file, partial, len) && ++count > n) {
516 res = ast_strdup(find->file);
520 AST_RWLIST_UNLOCK(&file_versions);
524 /*! \brief Find version for given module name */
525 const char *ast_file_version_find(const char *file)
527 struct file_version *iterator;
529 AST_RWLIST_WRLOCK(&file_versions);
530 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
531 if (!strcasecmp(iterator->file, file))
534 AST_RWLIST_UNLOCK(&file_versions);
536 return iterator->version;
540 struct thread_list_t {
541 AST_RWLIST_ENTRY(thread_list_t) list;
547 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
549 void ast_register_thread(char *name)
551 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
556 ast_assert(multi_thread_safe);
557 new->id = pthread_self();
558 new->lwp = ast_get_tid();
559 new->name = name; /* steal the allocated memory for the thread name */
560 AST_RWLIST_WRLOCK(&thread_list);
561 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
562 AST_RWLIST_UNLOCK(&thread_list);
565 void ast_unregister_thread(void *id)
567 struct thread_list_t *x;
569 AST_RWLIST_WRLOCK(&thread_list);
570 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
571 if ((void *) x->id == id) {
572 AST_RWLIST_REMOVE_CURRENT(list);
576 AST_RWLIST_TRAVERSE_SAFE_END;
577 AST_RWLIST_UNLOCK(&thread_list);
584 /*! \brief Give an overview of core settings */
585 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
593 e->command = "core show settings";
594 e->usage = "Usage: core show settings\n"
595 " Show core misc settings";
601 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
603 ast_cli(a->fd, "\nPBX Core settings\n");
604 ast_cli(a->fd, "-----------------\n");
605 ast_cli(a->fd, " Version: %s\n", ast_get_version());
606 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
608 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
610 ast_cli(a->fd, " Maximum calls: Not set\n");
612 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
614 ast_cli(a->fd, " Maximum open file handles: Not set\n");
615 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
616 ast_cli(a->fd, " Debug level: %d\n", option_debug);
617 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
618 #if defined(HAVE_SYSINFO)
619 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
621 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
622 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
623 ast_cli(a->fd, " Startup time: %s\n", buf);
625 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
626 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
627 ast_cli(a->fd, " Last reload time: %s\n", buf);
629 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);
630 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
631 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
632 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
633 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
634 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
635 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
636 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
637 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
638 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
639 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
640 ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
642 ast_cli(a->fd, "\n* Subsystems\n");
643 ast_cli(a->fd, " -------------\n");
644 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
645 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
646 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
647 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
649 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
651 ast_cli(a->fd, "\n* Directories\n");
652 ast_cli(a->fd, " -------------\n");
653 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
654 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
655 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
656 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
657 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
658 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
659 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
660 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
661 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
662 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
663 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
664 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
665 ast_cli(a->fd, "\n\n");
669 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
672 struct thread_list_t *cur;
675 e->command = "core show threads";
677 "Usage: core show threads\n"
678 " List threads currently active in the system.\n";
684 AST_RWLIST_RDLOCK(&thread_list);
685 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
686 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
689 AST_RWLIST_UNLOCK(&thread_list);
690 ast_cli(a->fd, "%d threads listed.\n", count);
694 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
696 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
697 * to be based on the new swapctl(2) system call.
699 static int swapmode(int *used, int *total)
701 struct swapent *swdev;
702 int nswap, rnswap, i;
704 nswap = swapctl(SWAP_NSWAP, 0, 0);
708 swdev = ast_calloc(nswap, sizeof(*swdev));
712 rnswap = swapctl(SWAP_STATS, swdev, nswap);
718 /* if rnswap != nswap, then what? */
720 /* Total things up */
722 for (i = 0; i < nswap; i++) {
723 if (swdev[i].se_flags & SWF_ENABLE) {
724 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
725 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
731 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
732 static int swapmode(int *used, int *total)
739 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
740 /*! \brief Give an overview of system statistics */
741 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
743 uint64_t physmem, freeram;
744 uint64_t freeswap = 0;
748 #if defined(HAVE_SYSINFO)
749 struct sysinfo sys_info;
751 uptime = sys_info.uptime / 3600;
752 physmem = sys_info.totalram * sys_info.mem_unit;
753 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
754 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
755 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
756 nprocs = sys_info.procs;
757 #elif defined(HAVE_SYSCTL)
758 static int pageshift;
759 struct vmtotal vmtotal;
760 struct timeval boottime;
762 int mib[2], pagesize, usedswap = 0;
764 /* calculate the uptime by looking at boottime */
767 mib[1] = KERN_BOOTTIME;
768 len = sizeof(boottime);
769 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
770 uptime = now - boottime.tv_sec;
772 uptime = uptime/3600;
773 /* grab total physical memory */
775 #if defined(HW_PHYSMEM64)
776 mib[1] = HW_PHYSMEM64;
780 len = sizeof(physmem);
781 sysctl(mib, 2, &physmem, &len, NULL, 0);
783 pagesize = getpagesize();
785 while (pagesize > 1) {
790 /* we only need the amount of log(2)1024 for our conversion */
796 len = sizeof(vmtotal);
797 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
798 freeram = (vmtotal.t_free << pageshift);
799 /* generate swap usage and totals */
800 swapmode(&usedswap, &totalswap);
801 freeswap = (totalswap - usedswap);
802 /* grab number of processes */
803 #if defined(__OpenBSD__)
805 mib[1] = KERN_NPROCS;
806 len = sizeof(nprocs);
807 sysctl(mib, 2, &nprocs, &len, NULL, 0);
813 e->command = "core show sysinfo";
815 "Usage: core show sysinfo\n"
816 " List current system information.\n";
822 ast_cli(a->fd, "\nSystem Statistics\n");
823 ast_cli(a->fd, "-----------------\n");
824 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
825 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
826 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
827 #if defined(HAVE_SYSINFO)
828 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
830 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
831 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
832 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
834 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
839 struct profile_entry {
841 uint64_t scale; /* if non-zero, values are scaled by this */
847 struct profile_data {
850 struct profile_entry e[0];
853 static struct profile_data *prof_data;
855 /*! \brief allocates a counter with a given name and scale.
856 * \return Returns the identifier of the counter.
858 int ast_add_profile(const char *name, uint64_t scale)
860 int l = sizeof(struct profile_data);
861 int n = 10; /* default entries */
863 if (prof_data == NULL) {
864 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
865 if (prof_data == NULL)
867 prof_data->entries = 0;
868 prof_data->max_size = n;
870 if (prof_data->entries >= prof_data->max_size) {
872 n = prof_data->max_size + 20;
873 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
877 prof_data->max_size = n;
879 n = prof_data->entries++;
880 prof_data->e[n].name = ast_strdup(name);
881 prof_data->e[n].value = 0;
882 prof_data->e[n].events = 0;
883 prof_data->e[n].mark = 0;
884 prof_data->e[n].scale = scale;
888 int64_t ast_profile(int i, int64_t delta)
890 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
892 if (prof_data->e[i].scale > 1)
893 delta /= prof_data->e[i].scale;
894 prof_data->e[i].value += delta;
895 prof_data->e[i].events++;
896 return prof_data->e[i].value;
899 /* The RDTSC instruction was introduced on the Pentium processor and is not
900 * implemented on certain clones, like the Cyrix 586. Hence, the previous
901 * expectation of __i386__ was in error. */
902 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
903 #if defined(__FreeBSD__)
904 #include <machine/cpufunc.h>
906 static __inline uint64_t
911 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
915 #else /* supply a dummy function on other platforms */
916 static __inline uint64_t
923 int64_t ast_mark(int i, int startstop)
925 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
928 prof_data->e[i].mark = rdtsc();
930 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
931 if (prof_data->e[i].scale > 1)
932 prof_data->e[i].mark /= prof_data->e[i].scale;
933 prof_data->e[i].value += prof_data->e[i].mark;
934 prof_data->e[i].events++;
936 return prof_data->e[i].mark;
939 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
940 max = prof_data->entries;\
941 if (a->argc > 3) { /* specific entries */ \
942 if (isdigit(a->argv[3][0])) { \
943 min = atoi(a->argv[3]); \
944 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
945 max = atoi(a->argv[4]); \
947 search = a->argv[3]; \
949 if (max > prof_data->entries) \
950 max = prof_data->entries;
952 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
955 const char *search = NULL;
958 e->command = "core show profile";
959 e->usage = "Usage: core show profile\n"
960 " show profile information";
966 if (prof_data == NULL)
969 DEFINE_PROFILE_MIN_MAX_VALUES;
970 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
971 prof_data->entries, prof_data->max_size);
972 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
973 "Value", "Average", "Name");
974 for (i = min; i < max; i++) {
975 struct profile_entry *entry = &prof_data->e[i];
976 if (!search || strstr(entry->name, search))
977 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
980 (long)entry->events, (long long)entry->value,
981 (long long)(entry->events ? entry->value / entry->events : entry->value),
987 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
990 const char *search = NULL;
993 e->command = "core clear profile";
994 e->usage = "Usage: core clear profile\n"
995 " clear profile information";
1001 if (prof_data == NULL)
1004 DEFINE_PROFILE_MIN_MAX_VALUES;
1005 for (i= min; i < max; i++) {
1006 if (!search || strstr(prof_data->e[i].name, search)) {
1007 prof_data->e[i].value = 0;
1008 prof_data->e[i].events = 0;
1013 #undef DEFINE_PROFILE_MIN_MAX_VALUES
1015 /*! \brief CLI command to list module versions */
1016 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1018 #define FORMAT "%-25.25s %-40.40s\n"
1019 struct file_version *iterator;
1021 int havepattern = 0;
1023 int count_files = 0;
1025 int matchlen, which = 0;
1026 struct file_version *find;
1030 e->command = "core show file version [like]";
1032 "Usage: core show file version [like <pattern>]\n"
1033 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
1034 " Optional regular expression pattern is used to filter the file list.\n";
1037 matchlen = strlen(a->word);
1040 AST_RWLIST_RDLOCK(&file_versions);
1041 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
1042 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
1043 ret = ast_strdup(find->file);
1047 AST_RWLIST_UNLOCK(&file_versions);
1054 if (!strcasecmp(a->argv[4], "like")) {
1055 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
1056 return CLI_SHOWUSAGE;
1059 return CLI_SHOWUSAGE;
1067 return CLI_SHOWUSAGE;
1070 ast_cli(a->fd, FORMAT, "File", "Revision");
1071 ast_cli(a->fd, FORMAT, "----", "--------");
1072 AST_RWLIST_RDLOCK(&file_versions);
1073 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
1074 if (havename && strcasecmp(iterator->file, a->argv[4]))
1077 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
1080 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
1085 AST_RWLIST_UNLOCK(&file_versions);
1087 ast_cli(a->fd, "%d files listed.\n", count_files);
1097 #endif /* ! LOW_MEMORY */
1099 struct stasis_topic *ast_system_topic(void)
1101 return system_topic;
1104 /*! \brief Cleanup the \ref stasis system level items */
1105 static void stasis_system_topic_cleanup(void)
1107 ao2_cleanup(system_topic);
1108 system_topic = NULL;
1109 STASIS_MESSAGE_TYPE_CLEANUP(ast_network_change_type);
1112 /*! \brief Initialize the system level items for \ref stasis */
1113 static int stasis_system_topic_init(void)
1115 ast_register_cleanup(stasis_system_topic_cleanup);
1117 system_topic = stasis_topic_create("ast_system");
1118 if (!system_topic) {
1122 if (STASIS_MESSAGE_TYPE_INIT(ast_network_change_type) != 0) {
1129 static void publish_fully_booted(void)
1131 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1133 json_object = ast_json_pack("{s: s}",
1134 "Status", "Fully Booted");
1135 ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
1138 static void ast_run_atexits(int run_cleanups)
1140 struct ast_atexit *ae;
1142 AST_LIST_LOCK(&atexits);
1143 while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1144 if (ae->func && (!ae->is_cleanup || run_cleanups)) {
1149 AST_LIST_UNLOCK(&atexits);
1152 static void __ast_unregister_atexit(void (*func)(void))
1154 struct ast_atexit *ae;
1156 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1157 if (ae->func == func) {
1158 AST_LIST_REMOVE_CURRENT(list);
1163 AST_LIST_TRAVERSE_SAFE_END;
1166 static int register_atexit(void (*func)(void), int is_cleanup)
1168 struct ast_atexit *ae;
1170 ae = ast_calloc(1, sizeof(*ae));
1175 ae->is_cleanup = is_cleanup;
1177 AST_LIST_LOCK(&atexits);
1178 __ast_unregister_atexit(func);
1179 AST_LIST_INSERT_HEAD(&atexits, ae, list);
1180 AST_LIST_UNLOCK(&atexits);
1185 int ast_register_atexit(void (*func)(void))
1187 return register_atexit(func, 0);
1190 int ast_register_cleanup(void (*func)(void))
1192 return register_atexit(func, 1);
1195 void ast_unregister_atexit(void (*func)(void))
1197 AST_LIST_LOCK(&atexits);
1198 __ast_unregister_atexit(func);
1199 AST_LIST_UNLOCK(&atexits);
1202 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1203 static int fdsend(int fd, const char *s)
1205 return write(fd, s, strlen(s) + 1);
1208 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1209 static int fdprint(int fd, const char *s)
1211 return write(fd, s, strlen(s));
1214 /*! \brief NULL handler so we can collect the child exit status */
1215 static void _null_sig_handler(int sig)
1219 static struct sigaction null_sig_handler = {
1220 .sa_handler = _null_sig_handler,
1221 .sa_flags = SA_RESTART,
1224 static struct sigaction ignore_sig_handler = {
1225 .sa_handler = SIG_IGN,
1228 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1229 /*! \brief Keep track of how many threads are currently trying to wait*() on
1232 static unsigned int safe_system_level = 0;
1233 static struct sigaction safe_system_prev_handler;
1235 void ast_replace_sigchld(void)
1239 ast_mutex_lock(&safe_system_lock);
1240 level = safe_system_level++;
1242 /* only replace the handler if it has not already been done */
1244 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1247 ast_mutex_unlock(&safe_system_lock);
1250 void ast_unreplace_sigchld(void)
1254 ast_mutex_lock(&safe_system_lock);
1255 level = --safe_system_level;
1257 /* only restore the handler if we are the last one */
1259 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1262 ast_mutex_unlock(&safe_system_lock);
1265 int ast_safe_system(const char *s)
1269 struct rusage rusage;
1272 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1273 ast_replace_sigchld();
1275 #ifdef HAVE_WORKING_FORK
1283 cap_t cap = cap_from_text("cap_net_admin-eip");
1285 if (cap_set_proc(cap)) {
1286 /* Careful with order! Logging cannot happen after we close FDs */
1287 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1291 #ifdef HAVE_WORKING_FORK
1292 if (ast_opt_high_priority)
1293 ast_set_priority(0);
1294 /* Close file descriptors and launch system command */
1295 ast_close_fds_above_n(STDERR_FILENO);
1297 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1299 } else if (pid > 0) {
1301 res = wait4(pid, &status, 0, &rusage);
1303 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1305 } else if (errno != EINTR)
1309 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1313 ast_unreplace_sigchld();
1314 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1322 * \brief enable or disable a logging level to a specified console
1324 void ast_console_toggle_loglevel(int fd, int level, int state)
1328 if (level >= NUMLOGLEVELS) {
1329 level = NUMLOGLEVELS - 1;
1332 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1333 if (fd == consoles[x].fd) {
1335 * Since the logging occurs when levels are false, set to
1336 * flipped iinput because this function accepts 0 as off and 1 as on
1338 consoles[x].levels[level] = state ? 0 : 1;
1345 * \brief mute or unmute a console from logging
1347 void ast_console_toggle_mute(int fd, int silent)
1350 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1351 if (fd == consoles[x].fd) {
1352 if (consoles[x].mute) {
1353 consoles[x].mute = 0;
1355 ast_cli(fd, "Console is not muted anymore.\n");
1357 consoles[x].mute = 1;
1359 ast_cli(fd, "Console is muted.\n");
1364 ast_cli(fd, "Couldn't find remote console.\n");
1368 * \brief log the string to all attached console clients
1370 static void ast_network_puts_mutable(const char *string, int level)
1373 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1374 if (consoles[x].mute)
1376 if (consoles[x].fd > -1) {
1377 if (!consoles[x].levels[level])
1378 fdprint(consoles[x].p[1], string);
1384 * \brief log the string to the console, and all attached
1387 void ast_console_puts_mutable(const char *string, int level)
1389 fputs(string, stdout);
1391 ast_network_puts_mutable(string, level);
1395 * \brief write the string to all attached console clients
1397 static void ast_network_puts(const char *string)
1400 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1401 if (consoles[x].fd > -1)
1402 fdprint(consoles[x].p[1], string);
1407 * \brief write the string to the console, and all attached
1410 void ast_console_puts(const char *string)
1412 fputs(string, stdout);
1414 ast_network_puts(string);
1417 static void network_verboser(const char *s)
1419 ast_network_puts_mutable(s, __LOG_VERBOSE);
1422 static pthread_t lthread;
1425 * \brief read() function supporting the reception of user credentials.
1427 * \param fd Socket file descriptor.
1428 * \param buffer Receive buffer.
1429 * \param size 'buffer' size.
1430 * \param con Console structure to set received credentials
1431 * \retval -1 on error
1432 * \retval the number of bytes received on success.
1434 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1436 #if defined(SO_PEERCRED)
1437 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1438 #define HAVE_STRUCT_UCRED_UID
1439 struct sockpeercred cred;
1443 socklen_t len = sizeof(cred);
1445 #if defined(HAVE_GETPEEREID)
1453 result = read(fd, buffer, size);
1458 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1459 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1462 #if defined(HAVE_STRUCT_UCRED_UID)
1465 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1468 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1470 #elif defined(HAVE_GETPEEREID)
1471 if (getpeereid(fd, &uid, &gid)) {
1483 static void *netconsole(void *vconsole)
1485 struct console *con = vconsole;
1486 char hostname[MAXHOSTNAMELEN] = "";
1489 const char * const end_buf = inbuf + sizeof(inbuf);
1490 char *start_read = inbuf;
1492 struct pollfd fds[2];
1494 if (gethostname(hostname, sizeof(hostname)-1))
1495 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1496 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1497 fdprint(con->fd, outbuf);
1499 fds[0].fd = con->fd;
1500 fds[0].events = POLLIN;
1502 fds[1].fd = con->p[0];
1503 fds[1].events = POLLIN;
1506 res = ast_poll(fds, 2, -1);
1509 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1512 if (fds[0].revents) {
1513 int cmds_read, bytes_read;
1514 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1517 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1518 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1519 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1522 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1523 * NULL and not trailing partial commands. */
1524 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1525 /* No commands were read. We either have a short read on the first command
1526 * with space left, or a command that is too long */
1527 if (start_read + bytes_read < end_buf) {
1528 start_read += bytes_read;
1530 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1535 if (start_read[bytes_read - 1] == '\0') {
1536 /* The read ended on a command boundary, start reading again at the head of inbuf */
1540 /* If we get this far, we have left over characters that have not been processed.
1541 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1542 * We are guaranteed to have at least cmds_read NULLs */
1543 while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1546 memmove(inbuf, start_read, end_buf - start_read);
1547 start_read = end_buf - start_read + inbuf;
1549 if (fds[1].revents) {
1550 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1552 ast_log(LOG_ERROR, "read returned %d\n", res);
1555 res = write(con->fd, outbuf, res);
1560 if (!ast_opt_hide_connect) {
1561 ast_verb(3, "Remote UNIX connection disconnected\n");
1571 static void *listener(void *unused)
1573 struct sockaddr_un sunaddr;
1578 struct pollfd fds[1];
1582 fds[0].fd = ast_socket;
1583 fds[0].events = POLLIN;
1584 s = ast_poll(fds, 1, -1);
1585 pthread_testcancel();
1588 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1591 len = sizeof(sunaddr);
1592 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1595 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1597 #if !defined(SO_PASSCRED)
1601 /* turn on socket credentials passing. */
1602 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1603 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1606 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1607 if (consoles[x].fd >= 0) {
1610 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1611 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1612 consoles[x].fd = -1;
1613 fdprint(s, "Server failed to create pipe\n");
1617 flags = fcntl(consoles[x].p[1], F_GETFL);
1618 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1620 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1621 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1622 to know if the user didn't send the credentials. */
1623 consoles[x].uid = -2;
1624 consoles[x].gid = -2;
1625 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1626 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1627 close(consoles[x].p[0]);
1628 close(consoles[x].p[1]);
1629 consoles[x].fd = -1;
1630 fdprint(s, "Server failed to spawn thread\n");
1635 if (x >= AST_MAX_CONNECTS) {
1636 fdprint(s, "No more connections allowed\n");
1637 ast_log(LOG_WARNING, "No more connections allowed\n");
1639 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1640 ast_verb(3, "Remote UNIX connection\n");
1648 static int ast_makesocket(void)
1650 struct sockaddr_un sunaddr;
1656 for (x = 0; x < AST_MAX_CONNECTS; x++)
1657 consoles[x].fd = -1;
1658 unlink(ast_config_AST_SOCKET);
1659 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1660 if (ast_socket < 0) {
1661 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1664 memset(&sunaddr, 0, sizeof(sunaddr));
1665 sunaddr.sun_family = AF_LOCAL;
1666 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1667 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1669 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1674 res = listen(ast_socket, 2);
1676 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1681 if (ast_register_verbose(network_verboser)) {
1682 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1685 if (ast_pthread_create_background(<hread, NULL, listener, NULL)) {
1686 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1691 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1693 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1694 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1699 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1701 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1702 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1707 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1708 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1710 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1713 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1715 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1716 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1722 static int ast_tryconnect(void)
1724 struct sockaddr_un sunaddr;
1726 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1727 if (ast_consock < 0) {
1728 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1731 memset(&sunaddr, 0, sizeof(sunaddr));
1732 sunaddr.sun_family = AF_LOCAL;
1733 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1734 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1743 /*! \brief Urgent handler
1745 * Called by soft_hangup to interrupt the poll, read, or other
1746 * system call. We don't actually need to do anything though.
1747 * Remember: Cannot EVER ast_log from within a signal handler
1749 static void _urg_handler(int num)
1754 static struct sigaction urg_handler = {
1755 .sa_handler = _urg_handler,
1756 .sa_flags = SA_RESTART,
1759 static void _hup_handler(int num)
1761 int a = 0, save_errno = errno;
1762 printf("Received HUP signal -- Reloading configs\n");
1764 execvp(_argv[0], _argv);
1765 sig_flags.need_reload = 1;
1766 if (sig_alert_pipe[1] != -1) {
1767 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1768 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1774 static struct sigaction hup_handler = {
1775 .sa_handler = _hup_handler,
1776 .sa_flags = SA_RESTART,
1779 static void _child_handler(int sig)
1781 /* Must not ever ast_log or ast_verbose within signal handler */
1782 int n, status, save_errno = errno;
1785 * Reap all dead children -- not just one
1787 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1789 if (n == 0 && option_debug)
1790 printf("Huh? Child handler, but nobody there?\n");
1794 static struct sigaction child_handler = {
1795 .sa_handler = _child_handler,
1796 .sa_flags = SA_RESTART,
1799 /*! \brief Set maximum open files */
1800 static void set_ulimit(int value)
1802 struct rlimit l = {0, 0};
1805 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1812 if (setrlimit(RLIMIT_NOFILE, &l)) {
1813 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1817 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1822 /*! \brief Set an X-term or screen title */
1823 static void set_title(char *text)
1825 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1826 fprintf(stdout, "\033]2;%s\007", text);
1829 static void set_icon(char *text)
1831 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1832 fprintf(stdout, "\033]1;%s\007", text);
1835 /*! \brief We set ourselves to a high priority, that we might pre-empt
1836 * everything else. If your PBX has heavy activity on it, this is a
1839 int ast_set_priority(int pri)
1841 struct sched_param sched;
1842 memset(&sched, 0, sizeof(sched));
1845 sched.sched_priority = 10;
1846 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1847 ast_log(LOG_WARNING, "Unable to set high priority\n");
1850 ast_verb(1, "Set to realtime thread\n");
1852 sched.sched_priority = 0;
1853 /* According to the manpage, these parameters can never fail. */
1854 sched_setscheduler(0, SCHED_OTHER, &sched);
1858 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1859 ast_log(LOG_WARNING, "Unable to set high priority\n");
1862 ast_verb(1, "Set to high priority\n");
1864 /* According to the manpage, these parameters can never fail. */
1865 setpriority(PRIO_PROCESS, 0, 0);
1871 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1872 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1874 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1876 if (can_safely_quit(niceness, restart)) {
1877 really_quit(num, niceness, restart);
1878 /* No one gets here. */
1880 /* It wasn't our time. */
1883 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1885 /* Check if someone else isn't already doing this. */
1886 ast_mutex_lock(&safe_system_lock);
1887 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1888 /* Already in progress and other request was less nice. */
1889 ast_mutex_unlock(&safe_system_lock);
1890 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1893 shuttingdown = niceness;
1894 ast_mutex_unlock(&safe_system_lock);
1896 /* Try to get as many CDRs as possible submitted to the backend engines
1897 * (if in batch mode). really_quit happens to call it again when running
1898 * the atexit handlers, otherwise this would be a bit early. */
1899 ast_cdr_engine_term();
1901 /* Shutdown the message queue for the technology agnostic message channel.
1902 * This has to occur before we pause shutdown pending ast_undestroyed_channels. */
1905 if (niceness == SHUTDOWN_NORMAL) {
1907 /* Begin shutdown routine, hanging up active channels */
1908 ast_begin_shutdown(1);
1909 if (option_verbose && ast_opt_console) {
1910 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1915 /* Wait up to 15 seconds for all channels to go away */
1916 if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1919 /* Sleep 1/10 of a second */
1922 } else if (niceness >= SHUTDOWN_NICE) {
1923 if (niceness != SHUTDOWN_REALLY_NICE) {
1924 ast_begin_shutdown(0);
1926 if (option_verbose && ast_opt_console) {
1927 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1930 if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1937 /* Re-acquire lock and check if someone changed the niceness, in which
1938 * case someone else has taken over the shutdown.
1940 ast_mutex_lock(&safe_system_lock);
1941 if (shuttingdown != niceness) {
1942 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1943 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1945 ast_mutex_unlock(&safe_system_lock);
1948 shuttingdown = SHUTTING_DOWN;
1949 ast_mutex_unlock(&safe_system_lock);
1954 /*! Called when exiting is certain. */
1955 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1957 int active_channels;
1958 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1959 int run_cleanups = niceness >= SHUTDOWN_NICE;
1962 ast_module_shutdown();
1965 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1966 char filename[80] = "";
1967 if (getenv("HOME")) {
1968 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1970 if (!ast_strlen_zero(filename)) {
1971 ast_el_write_history(filename);
1973 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1974 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1978 if (el_hist != NULL) {
1979 history_end(el_hist);
1981 } else if (mon_sig_flags == pthread_self()) {
1982 if (consolethread != AST_PTHREADT_NULL) {
1983 pthread_kill(consolethread, SIGURG);
1987 active_channels = ast_active_channels();
1988 /* Don't publish messages if we're a remote console - we won't have all of the Stasis
1989 * topics or message types
1991 if (!ast_opt_remote) {
1992 json_object = ast_json_pack("{s: s, s: s}",
1993 "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
1994 "Restart", restart ? "True" : "False");
1995 ast_manager_publish_event("Shutdown", EVENT_FLAG_SYSTEM, json_object);
1997 ast_verb(0, "Asterisk %s ending (%d).\n",
1998 active_channels ? "uncleanly" : "cleanly", num);
2000 ast_verb(0, "Executing last minute cleanups\n");
2001 ast_run_atexits(run_cleanups);
2003 ast_debug(1, "Asterisk ending (%d).\n", num);
2004 if (ast_socket > -1) {
2005 pthread_cancel(lthread);
2008 unlink(ast_config_AST_SOCKET);
2010 if (ast_consock > -1)
2012 if (!ast_opt_remote)
2013 unlink(ast_config_AST_PID);
2014 printf("%s", term_quit());
2017 ast_verb(0, "Preparing for Asterisk restart...\n");
2018 /* Mark all FD's for closing on exec */
2019 for (i = 3; i < 32768; i++) {
2020 fcntl(i, F_SETFD, FD_CLOEXEC);
2022 ast_verb(0, "Asterisk is now restarting...\n");
2029 /* If there is a consolethread running send it a SIGHUP
2030 so it can execvp, otherwise we can do it ourselves */
2031 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
2032 pthread_kill(consolethread, SIGHUP);
2033 /* Give the signal handler some time to complete */
2036 execvp(_argv[0], _argv);
2047 static void __quit_handler(int num)
2050 sig_flags.need_quit = 1;
2051 if (sig_alert_pipe[1] != -1) {
2052 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
2053 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
2056 /* There is no need to restore the signal handler here, since the app
2057 * is going to exit */
2060 static void __remote_quit_handler(int num)
2062 sig_flags.need_quit = 1;
2065 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
2069 if (!strncmp(s, cmp, strlen(cmp))) {
2070 c = s + strlen(cmp);
2071 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
2077 /* These gymnastics are due to platforms which designate char as unsigned by
2078 * default. Level is the negative character -- offset by 1, because \0 is the
2080 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
2081 #define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
2083 static void console_verboser(const char *s)
2086 const char *c = NULL;
2089 if (VERBOSE_HASMAGIC(s)) {
2090 level = VERBOSE_MAGIC2LEVEL(s);
2092 if (level > option_verbose) {
2097 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
2098 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
2099 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
2100 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
2109 /* Wake up a poll()ing console */
2110 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2111 pthread_kill(consolethread, SIGURG);
2115 static int ast_all_zeros(char *s)
2125 static void consolehandler(char *s)
2127 printf("%s", term_end());
2130 /* Called when readline data is available */
2131 if (!ast_all_zeros(s))
2132 ast_el_add_history(s);
2133 /* The real handler for bang */
2136 ast_safe_system(s+1);
2138 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2140 ast_cli_command(STDOUT_FILENO, s);
2143 static int remoteconsolehandler(char *s)
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 } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2158 int old_verbose = option_verbose;
2159 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2161 if (sscanf(s + 25, "%d", &tmp) != 1) {
2162 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2164 if (tmp > option_verbose) {
2165 option_verbose = tmp;
2167 if (old_verbose != option_verbose) {
2168 fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2170 fprintf(stdout, "Verbosity level unchanged.\n");
2174 if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2175 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2177 if (old_verbose != option_verbose) {
2178 fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2180 fprintf(stdout, "Verbosity level unchanged.\n");
2185 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2186 (s[4] == '\0' || isspace(s[4]))) {
2187 quit_handler(0, SHUTDOWN_FAST, 0);
2194 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2198 e->command = "core show version";
2200 "Usage: core show version\n"
2201 " Shows Asterisk version information.\n";
2208 return CLI_SHOWUSAGE;
2209 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2210 ast_get_version(), ast_build_user, ast_build_hostname,
2211 ast_build_machine, ast_build_os, ast_build_date);
2216 static int handle_quit(int fd, int argc, char *argv[])
2219 return RESULT_SHOWUSAGE;
2220 quit_handler(0, SHUTDOWN_NORMAL, 0);
2221 return RESULT_SUCCESS;
2225 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2229 e->command = "core stop now";
2231 "Usage: core stop now\n"
2232 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2238 if (a->argc != e->args)
2239 return CLI_SHOWUSAGE;
2240 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2244 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2248 e->command = "core stop gracefully";
2250 "Usage: core stop gracefully\n"
2251 " Causes Asterisk to not accept new calls, and exit when all\n"
2252 " active calls have terminated normally.\n";
2258 if (a->argc != e->args)
2259 return CLI_SHOWUSAGE;
2260 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2264 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2268 e->command = "core stop when convenient";
2270 "Usage: core stop when convenient\n"
2271 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2277 if (a->argc != e->args)
2278 return CLI_SHOWUSAGE;
2279 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2280 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2284 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2288 e->command = "core restart now";
2290 "Usage: core restart now\n"
2291 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2298 if (a->argc != e->args)
2299 return CLI_SHOWUSAGE;
2300 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2304 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2308 e->command = "core restart gracefully";
2310 "Usage: core restart gracefully\n"
2311 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2312 " restart when all active calls have ended.\n";
2318 if (a->argc != e->args)
2319 return CLI_SHOWUSAGE;
2320 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2324 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2328 e->command = "core restart when convenient";
2330 "Usage: core restart when convenient\n"
2331 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2337 if (a->argc != e->args)
2338 return CLI_SHOWUSAGE;
2339 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2340 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2344 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2346 int aborting_shutdown = 0;
2350 e->command = "core abort shutdown";
2352 "Usage: core abort shutdown\n"
2353 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2354 " call operations.\n";
2360 if (a->argc != e->args)
2361 return CLI_SHOWUSAGE;
2363 ast_mutex_lock(&safe_system_lock);
2364 if (shuttingdown >= SHUTDOWN_FAST) {
2365 aborting_shutdown = 1;
2366 shuttingdown = NOT_SHUTTING_DOWN;
2368 ast_mutex_unlock(&safe_system_lock);
2370 if (aborting_shutdown) {
2371 ast_cancel_shutdown();
2376 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2382 "Usage: !<command>\n"
2383 " Executes a given shell command\n";
2391 static const char warranty_lines[] = {
2395 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2396 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2397 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2398 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2399 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2400 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2401 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2402 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2403 "REPAIR OR CORRECTION.\n"
2405 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2406 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2407 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2408 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2409 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2410 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2411 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2412 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2413 "POSSIBILITY OF SUCH DAMAGES.\n"
2416 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2420 e->command = "core show warranty";
2422 "Usage: core show warranty\n"
2423 " Shows the warranty (if any) for this copy of Asterisk.\n";
2429 ast_cli(a->fd, "%s", warranty_lines);
2434 static const char license_lines[] = {
2436 "This program is free software; you can redistribute it and/or modify\n"
2437 "it under the terms of the GNU General Public License version 2 as\n"
2438 "published by the Free Software Foundation.\n"
2440 "This program also contains components licensed under other licenses.\n"
2443 "This program is distributed in the hope that it will be useful,\n"
2444 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2445 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2446 "GNU General Public License for more details.\n"
2448 "You should have received a copy of the GNU General Public License\n"
2449 "along with this program; if not, write to the Free Software\n"
2450 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2453 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2457 e->command = "core show license";
2459 "Usage: core show license\n"
2460 " Shows the license(s) for this copy of Asterisk.\n";
2466 ast_cli(a->fd, "%s", license_lines);
2471 #define ASTERISK_PROMPT "*CLI> "
2473 #define ASTERISK_PROMPT2 "%s*CLI> "
2476 * \brief Shutdown Asterisk CLI commands.
2478 * \note These CLI commands cannot be unregistered at shutdown
2479 * because one of them is likely the reason for the shutdown.
2480 * The CLI generates a warning if a command is in-use when it is
2483 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2484 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2485 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2486 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2487 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2488 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2489 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2492 static struct ast_cli_entry cli_asterisk[] = {
2493 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2494 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2495 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2496 AST_CLI_DEFINE(handle_version, "Display version info"),
2497 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2498 #if !defined(LOW_MEMORY)
2499 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2500 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2501 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2502 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2504 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2505 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2506 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2507 #endif /* ! LOW_MEMORY */
2510 struct el_read_char_state_struct {
2511 unsigned int line_full:1;
2512 unsigned int prev_line_full:1;
2513 char prev_line_verbosity;
2516 static int el_read_char_state_init(void *ptr)
2518 struct el_read_char_state_struct *state = ptr;
2519 state->line_full = 1;
2520 state->prev_line_full = 1;
2521 state->prev_line_verbosity = 0;
2525 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2527 static int ast_el_read_char(EditLine *editline, char *cp)
2531 struct pollfd fds[2];
2534 #define EL_BUF_SIZE 512
2535 char buf[EL_BUF_SIZE];
2536 struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2540 fds[0].fd = ast_consock;
2541 fds[0].events = POLLIN;
2542 if (!ast_opt_exec) {
2543 fds[1].fd = STDIN_FILENO;
2544 fds[1].events = POLLIN;
2547 res = ast_poll(fds, max, -1);
2549 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2553 fprintf(stderr, "poll failed: %s\n", strerror(errno));
2557 if (!ast_opt_exec && fds[1].revents) {
2558 num_read = read(STDIN_FILENO, cp, 1);
2565 if (fds[0].revents) {
2567 char *curline = buf, *nextline;
2568 res = read(ast_consock, buf, sizeof(buf) - 1);
2569 /* if the remote side disappears exit */
2571 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2572 if (!ast_opt_reconnect) {
2573 quit_handler(0, SHUTDOWN_FAST, 0);
2576 int reconnects_per_second = 20;
2577 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2578 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2579 if (ast_tryconnect()) {
2580 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2581 printf("%s", term_quit());
2584 fdsend(ast_consock, "logger mute silent");
2586 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2589 usleep(1000000 / reconnects_per_second);
2591 if (tries >= 30 * reconnects_per_second) {
2592 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2593 quit_handler(0, SHUTDOWN_FAST, 0);
2601 /* Write over the CLI prompt */
2602 if (!ast_opt_exec && !lastpos) {
2603 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2608 state->prev_line_full = state->line_full;
2609 if ((nextline = strchr(curline, '\n'))) {
2610 state->line_full = 1;
2613 state->line_full = 0;
2614 nextline = strchr(curline, '\0');
2617 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2618 level = VERBOSE_MAGIC2LEVEL(curline);
2620 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2621 /* Non-verbose output */
2624 level = state->prev_line_verbosity;
2626 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2627 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2631 state->prev_line_verbosity = level;
2633 } while (!ast_strlen_zero(curline));
2635 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2647 static struct ast_str *prompt = NULL;
2649 static char *cli_prompt(EditLine *editline)
2654 static int cli_prompt_changes = 0;
2658 if (prompt == NULL) {
2659 prompt = ast_str_create(100);
2660 } else if (!cli_prompt_changes) {
2661 return ast_str_buffer(prompt);
2663 ast_str_reset(prompt);
2666 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2668 struct timeval ts = ast_tvnow();
2669 while (*t != '\0') {
2671 char hostname[MAXHOSTNAMELEN] = "";
2673 struct ast_tm tm = { 0, };
2674 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2678 case 'C': /* color */
2680 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2681 ast_term_color_code(&prompt, fgcolor, bgcolor);
2683 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2684 ast_term_color_code(&prompt, fgcolor, 0);
2688 /* If the color has been reset correctly, then there's no need to reset it later */
2689 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2691 case 'd': /* date */
2692 if (ast_localtime(&ts, &tm, NULL)) {
2693 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2694 ast_str_append(&prompt, 0, "%s", tmp);
2695 cli_prompt_changes++;
2698 case 'g': /* group */
2699 if ((gr = getgrgid(getgid()))) {
2700 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2703 case 'h': /* hostname */
2704 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2705 ast_str_append(&prompt, 0, "%s", hostname);
2707 ast_str_append(&prompt, 0, "%s", "localhost");
2710 case 'H': /* short hostname */
2711 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2713 if ((dotptr = strchr(hostname, '.'))) {
2716 ast_str_append(&prompt, 0, "%s", hostname);
2718 ast_str_append(&prompt, 0, "%s", "localhost");
2721 #ifdef HAVE_GETLOADAVG
2722 case 'l': /* load avg */
2724 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2726 getloadavg(list, 3);
2727 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2728 cli_prompt_changes++;
2732 case 's': /* Asterisk system name (from asterisk.conf) */
2733 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2735 case 't': /* time */
2736 if (ast_localtime(&ts, &tm, NULL)) {
2737 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2738 ast_str_append(&prompt, 0, "%s", tmp);
2739 cli_prompt_changes++;
2742 case 'u': /* username */
2743 if ((pw = getpwuid(getuid()))) {
2744 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2747 case '#': /* process console or remote? */
2748 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2750 case '%': /* literal % */
2751 ast_str_append(&prompt, 0, "%c", '%');
2753 case '\0': /* % is last character - prevent bug */
2758 ast_str_append(&prompt, 0, "%c", *t);
2763 /* Force colors back to normal at end */
2764 ast_term_color_code(&prompt, 0, 0);
2766 } else if (remotehostname) {
2767 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2769 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2772 return ast_str_buffer(prompt);
2775 static char **ast_el_strtoarr(char *buf)
2777 char **match_list = NULL, **match_list_tmp, *retstr;
2778 size_t match_list_len;
2782 while ( (retstr = strsep(&buf, " ")) != NULL) {
2784 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2786 if (matches + 1 >= match_list_len) {
2787 match_list_len <<= 1;
2788 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2789 match_list = match_list_tmp;
2792 ast_free(match_list);
2793 return (char **) NULL;
2797 match_list[matches++] = ast_strdup(retstr);
2801 return (char **) NULL;
2803 if (matches >= match_list_len) {
2804 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2805 match_list = match_list_tmp;
2808 ast_free(match_list);
2809 return (char **) NULL;
2813 match_list[matches] = (char *) NULL;
2818 static int ast_el_sort_compare(const void *i1, const void *i2)
2822 s1 = ((char **)i1)[0];
2823 s2 = ((char **)i2)[0];
2825 return strcasecmp(s1, s2);
2828 static int ast_cli_display_match_list(char **matches, int len, int max)
2830 int i, idx, limit, count;
2831 int screenwidth = 0;
2832 int numoutput = 0, numoutputline = 0;
2834 screenwidth = ast_get_termcols(STDOUT_FILENO);
2836 /* find out how many entries can be put on one line, with two spaces between strings */
2837 limit = screenwidth / (max + 2);
2841 /* how many lines of output */
2842 count = len / limit;
2843 if (count * limit < len)
2848 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2850 for (; count > 0; count--) {
2852 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2854 /* Don't print dupes */
2855 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2857 ast_free(matches[idx]);
2858 matches[idx] = NULL;
2864 fprintf(stdout, "%-*s ", max, matches[idx]);
2865 ast_free(matches[idx]);
2866 matches[idx] = NULL;
2868 if (numoutputline > 0)
2869 fprintf(stdout, "\n");
2876 static char *cli_complete(EditLine *editline, int ch)
2882 int retval = CC_ERROR;
2883 char buf[2048], savechr;
2886 LineInfo *lf = (LineInfo *)el_line(editline);
2888 savechr = *(char *)lf->cursor;
2889 *(char *)lf->cursor = '\0';
2890 ptr = (char *)lf->cursor;
2892 while (ptr > lf->buffer) {
2893 if (isspace(*ptr)) {
2901 len = lf->cursor - ptr;
2903 if (ast_opt_remote) {
2904 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2905 fdsend(ast_consock, buf);
2906 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2907 return (char*)(CC_ERROR);
2910 nummatches = atoi(buf);
2912 if (nummatches > 0) {
2914 int mlen = 0, maxmbuf = 2048;
2915 /* Start with a 2048 byte buffer */
2916 if (!(mbuf = ast_malloc(maxmbuf))) {
2917 *((char *) lf->cursor) = savechr;
2918 return (char *)(CC_ERROR);
2920 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2921 fdsend(ast_consock, buf);
2924 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2925 if (mlen + 1024 > maxmbuf) {
2926 /* Every step increment buffer 1024 bytes */
2928 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2929 *((char *) lf->cursor) = savechr;
2930 return (char *)(CC_ERROR);
2933 /* Only read 1024 bytes at a time */
2934 res = read(ast_consock, mbuf + mlen, 1024);
2940 matches = ast_el_strtoarr(mbuf);
2943 matches = (char **) NULL;
2945 char **p, *oldbuf=NULL;
2947 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2948 for (p = matches; p && *p; p++) {
2949 if (!oldbuf || strcmp(*p,oldbuf))
2957 int matches_num, maxlen, match_len;
2959 if (matches[0][0] != '\0') {
2960 el_deletestr(editline, (int) len);
2961 el_insertstr(editline, matches[0]);
2962 retval = CC_REFRESH;
2965 if (nummatches == 1) {
2966 /* Found an exact match */
2967 el_insertstr(editline, " ");
2968 retval = CC_REFRESH;
2970 /* Must be more than one match */
2971 for (i = 1, maxlen = 0; matches[i]; i++) {
2972 match_len = strlen(matches[i]);
2973 if (match_len > maxlen)
2976 matches_num = i - 1;
2977 if (matches_num >1) {
2978 fprintf(stdout, "\n");
2979 ast_cli_display_match_list(matches, nummatches, maxlen);
2980 retval = CC_REDISPLAY;
2982 el_insertstr(editline," ");
2983 retval = CC_REFRESH;
2986 for (i = 0; matches[i]; i++)
2987 ast_free(matches[i]);
2991 *((char *) lf->cursor) = savechr;
2993 return (char *)(long)retval;
2996 static int ast_el_initialize(void)
2999 char *editor, *editrc = getenv("EDITRC");
3001 if (!(editor = getenv("AST_EDITMODE"))) {
3002 if (!(editor = getenv("AST_EDITOR"))) {
3009 if (el_hist != NULL)
3010 history_end(el_hist);
3012 el = el_init("asterisk", stdin, stdout, stderr);
3013 el_set(el, EL_PROMPT, cli_prompt);
3015 el_set(el, EL_EDITMODE, 1);
3016 el_set(el, EL_EDITOR, editor);
3017 el_hist = history_init();
3018 if (!el || !el_hist)
3021 /* setup history with 100 entries */
3022 history(el_hist, &ev, H_SETSIZE, 100);
3024 el_set(el, EL_HIST, history, el_hist);
3026 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
3027 /* Bind <tab> to command completion */
3028 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
3029 /* Bind ? to command completion */
3030 el_set(el, EL_BIND, "?", "ed-complete", NULL);
3031 /* Bind ^D to redisplay */
3032 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
3033 /* Bind Delete to delete char left */
3034 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
3035 /* Bind Home and End to move to line start and end */
3036 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3037 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3038 /* Bind C-left and C-right to move by word (not all terminals) */
3039 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
3040 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
3043 el_source(el, editrc);
3049 #define MAX_HISTORY_COMMAND_LENGTH 256
3051 static int ast_el_add_history(char *buf)
3055 if (el_hist == NULL || el == NULL)
3056 ast_el_initialize();
3057 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
3059 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
3062 static int ast_el_write_history(char *filename)
3066 if (el_hist == NULL || el == NULL)
3067 ast_el_initialize();
3069 return (history(el_hist, &ev, H_SAVE, filename));
3072 static int ast_el_read_history(char *filename)
3076 if (el_hist == NULL || el == NULL) {
3077 ast_el_initialize();
3080 return history(el_hist, &ev, H_LOAD, filename);
3083 static void ast_remotecontrol(char *data)
3087 char filename[80] = "";
3092 char *stringp = NULL;
3097 memset(&sig_flags, 0, sizeof(sig_flags));
3098 signal(SIGINT, __remote_quit_handler);
3099 signal(SIGTERM, __remote_quit_handler);
3100 signal(SIGHUP, __remote_quit_handler);
3102 if (read(ast_consock, buf, sizeof(buf)) < 0) {
3103 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3107 char prefix[] = "cli quit after ";
3108 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3109 sprintf(tmp, "%s%s", prefix, data);
3110 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3111 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3112 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3118 hostname = strsep(&stringp, "/");
3119 cpid = strsep(&stringp, "/");
3120 version = strsep(&stringp, "\n");
3122 version = "<Version Unknown>";
3124 strsep(&stringp, ".");
3130 if (!ast_opt_mute) {
3131 fdsend(ast_consock, "logger mute silent");
3133 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3137 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
3138 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3140 fds.fd = ast_consock;
3141 fds.events = POLLIN;
3144 while (ast_poll(&fds, 1, 60000) > 0) {
3145 char buffer[512] = "", *curline = buffer, *nextline;
3146 int not_written = 1;
3148 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3152 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3157 prev_linefull = linefull;
3158 if ((nextline = strchr(curline, '\n'))) {
3163 nextline = strchr(curline, '\0');
3166 /* Skip verbose lines */
3167 /* Prev line full? | Line is verbose | Last line verbose? | Print
3168 * TRUE | TRUE* | TRUE | FALSE
3169 * TRUE | TRUE* | FALSE | FALSE
3170 * TRUE | FALSE* | TRUE | TRUE
3171 * TRUE | FALSE* | FALSE | TRUE
3172 * FALSE | TRUE | TRUE* | FALSE
3173 * FALSE | TRUE | FALSE* | TRUE
3174 * FALSE | FALSE | TRUE* | FALSE
3175 * FALSE | FALSE | FALSE* | TRUE
3177 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3178 prev_line_verbose = 0;
3180 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3181 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3184 prev_line_verbose = 1;
3187 } while (!ast_strlen_zero(curline));