2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2014, 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 - 2014, 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 rel="nofollow" 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/pickup.h"
206 #include "asterisk/features.h"
207 #include "asterisk/acl.h"
208 #include "asterisk/ulaw.h"
209 #include "asterisk/alaw.h"
210 #include "asterisk/callerid.h"
211 #include "asterisk/image.h"
212 #include "asterisk/tdd.h"
213 #include "asterisk/term.h"
214 #include "asterisk/manager.h"
215 #include "asterisk/cdr.h"
216 #include "asterisk/cel.h"
217 #include "asterisk/pbx.h"
218 #include "asterisk/enum.h"
219 #include "asterisk/http.h"
220 #include "asterisk/udptl.h"
221 #include "asterisk/app.h"
222 #include "asterisk/lock.h"
223 #include "asterisk/utils.h"
224 #include "asterisk/file.h"
225 #include "asterisk/io.h"
226 #include "editline/histedit.h"
227 #include "asterisk/config.h"
228 #include "asterisk/ast_version.h"
229 #include "asterisk/linkedlists.h"
230 #include "asterisk/devicestate.h"
231 #include "asterisk/presencestate.h"
232 #include "asterisk/module.h"
233 #include "asterisk/dsp.h"
234 #include "asterisk/buildinfo.h"
235 #include "asterisk/xmldoc.h"
236 #include "asterisk/poll-compat.h"
237 #include "asterisk/ccss.h"
238 #include "asterisk/test.h"
239 #include "asterisk/rtp_engine.h"
240 #include "asterisk/format.h"
241 #include "asterisk/aoc.h"
242 #include "asterisk/uuid.h"
243 #include "asterisk/sorcery.h"
244 #include "asterisk/bucket.h"
245 #include "asterisk/stasis.h"
246 #include "asterisk/json.h"
247 #include "asterisk/stasis_endpoints.h"
248 #include "asterisk/stasis_system.h"
249 #include "asterisk/security_events.h"
250 #include "asterisk/endpoints.h"
251 #include "asterisk/codec.h"
252 #include "asterisk/format_cache.h"
254 #include "../defaults.h"
257 <managerEvent language="en_US" name="FullyBooted">
258 <managerEventInstance class="EVENT_FLAG_SYSTEM">
259 <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
261 <parameter name="Status">
262 <para>Informational message</para>
265 </managerEventInstance>
267 <managerEvent language="en_US" name="Shutdown">
268 <managerEventInstance class="EVENT_FLAG_SYSTEM">
269 <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
271 <parameter name="Shutdown">
272 <para>Whether the shutdown is proceeding cleanly (all channels
273 were hungup successfully) or uncleanly (channels will be
276 <enum name="Uncleanly"/>
277 <enum name="Cleanly"/>
280 <parameter name="Restart">
281 <para>Whether or not a restart will occur.</para>
288 </managerEventInstance>
293 #define AF_LOCAL AF_UNIX
294 #define PF_LOCAL PF_UNIX
297 #define AST_MAX_CONNECTS 128
300 /*! Default minimum DTMF digit length - 80ms */
301 #define AST_MIN_DTMF_DURATION 80
304 /*! \brief Welcome message when starting a CLI interface */
305 #define WELCOME_MESSAGE \
306 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2014, Digium, Inc. and others.\n" \
307 "Created by Mark Spencer <markster@digium.com>\n" \
308 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
309 "This is free software, with components licensed under the GNU General Public\n" \
310 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
311 "certain conditions. Type 'core show license' for details.\n" \
312 "=========================================================================\n", ast_get_version()) \
314 /*! \defgroup main_options Main Configuration Options
315 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
316 * \arg \ref Config_ast "asterisk.conf"
317 * \note Some of them can be changed in the CLI
321 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
323 /*! Maximum active system verbosity level. */
324 int ast_verb_sys_level;
326 int option_verbose; /*!< Verbosity level */
327 int option_debug; /*!< Debug level */
328 double ast_option_maxload; /*!< Max load avg on system */
329 int ast_option_maxcalls; /*!< Max number of active calls */
330 int ast_option_maxfiles; /*!< Max number of open file handles (files, sockets) */
331 unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */
332 #if defined(HAVE_SYSINFO)
333 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
338 struct ast_eid ast_eid_default;
340 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
341 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
343 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
344 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
347 int fd; /*!< File descriptor */
348 int p[2]; /*!< Pipe */
349 pthread_t t; /*!< Thread of handler */
350 int mute; /*!< Is the console muted for logs */
351 int uid; /*!< Remote user ID. */
352 int gid; /*!< Remote group ID. */
353 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
354 /*! Verbosity level of this console. */
361 AST_LIST_ENTRY(ast_atexit) list;
364 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
366 struct timeval ast_startuptime;
367 struct timeval ast_lastreloadtime;
369 static History *el_hist;
371 static char *remotehostname;
373 struct console consoles[AST_MAX_CONNECTS];
375 char ast_defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
377 static int ast_el_add_history(char *);
378 static int ast_el_read_history(char *);
379 static int ast_el_write_history(char *);
382 char config_dir[PATH_MAX];
383 char module_dir[PATH_MAX];
384 char spool_dir[PATH_MAX];
385 char monitor_dir[PATH_MAX];
386 char recording_dir[PATH_MAX];
387 char var_dir[PATH_MAX];
388 char data_dir[PATH_MAX];
389 char log_dir[PATH_MAX];
390 char agi_dir[PATH_MAX];
391 char run_dir[PATH_MAX];
392 char key_dir[PATH_MAX];
394 char config_file[PATH_MAX];
395 char db_path[PATH_MAX];
396 char sbin_dir[PATH_MAX];
397 char pid_path[PATH_MAX];
398 char socket_path[PATH_MAX];
399 char run_user[PATH_MAX];
400 char run_group[PATH_MAX];
401 char system_name[128];
404 static struct _cfg_paths cfg_paths;
406 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
407 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
408 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
409 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
410 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
411 const char *ast_config_AST_RECORDING_DIR = cfg_paths.recording_dir;
412 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
413 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
414 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
415 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
416 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
417 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
418 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
420 const char *ast_config_AST_DB = cfg_paths.db_path;
421 const char *ast_config_AST_PID = cfg_paths.pid_path;
422 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
423 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
424 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
425 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
427 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
428 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
429 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
430 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
432 extern unsigned int ast_FD_SETSIZE;
434 static char *_argv[256];
437 /*! Normal operation */
439 /*! Committed to shutting down. Final phase */
441 /*! Committed to shutting down. Initial phase */
444 * Valid values for quit_handler() niceness below.
445 * These shutdown/restart levels can be cancelled.
447 * Remote console exit right now
450 /*! core stop/restart now */
452 /*! core stop/restart gracefully */
454 /*! core stop/restart when convenient */
458 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
460 /*! Prevent new channel allocation for shutdown. */
461 static int shutdown_pending;
463 static int restartnow;
464 static pthread_t consolethread = AST_PTHREADT_NULL;
465 static pthread_t mon_sig_flags;
466 static int canary_pid = 0;
467 static char canary_filename[128];
468 static int multi_thread_safe;
470 static char randompool[256];
472 static int sig_alert_pipe[2] = { -1, -1 };
474 unsigned int need_reload:1;
475 unsigned int need_quit:1;
476 unsigned int need_quit_handler:1;
479 #if !defined(LOW_MEMORY)
480 struct file_version {
481 AST_RWLIST_ENTRY(file_version) list;
486 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
488 void ast_register_file_version(const char *file, const char *version)
490 struct file_version *new;
492 size_t version_length;
494 work = ast_strdupa(version);
495 work = ast_strip(ast_strip_quoted(work, "$", "$"));
496 version_length = strlen(work) + 1;
498 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
502 new->version = (char *) new + sizeof(*new);
503 memcpy(new->version, work, version_length);
504 AST_RWLIST_WRLOCK(&file_versions);
505 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
506 AST_RWLIST_UNLOCK(&file_versions);
509 void ast_unregister_file_version(const char *file)
511 struct file_version *find;
513 AST_RWLIST_WRLOCK(&file_versions);
514 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
515 if (!strcasecmp(find->file, file)) {
516 AST_RWLIST_REMOVE_CURRENT(list);
520 AST_RWLIST_TRAVERSE_SAFE_END;
521 AST_RWLIST_UNLOCK(&file_versions);
527 char *ast_complete_source_filename(const char *partial, int n)
529 struct file_version *find;
530 size_t len = strlen(partial);
534 AST_RWLIST_RDLOCK(&file_versions);
535 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
536 if (!strncasecmp(find->file, partial, len) && ++count > n) {
537 res = ast_strdup(find->file);
541 AST_RWLIST_UNLOCK(&file_versions);
545 /*! \brief Find version for given module name */
546 const char *ast_file_version_find(const char *file)
548 struct file_version *iterator;
550 AST_RWLIST_WRLOCK(&file_versions);
551 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
552 if (!strcasecmp(iterator->file, file))
555 AST_RWLIST_UNLOCK(&file_versions);
557 return iterator->version;
561 struct thread_list_t {
562 AST_RWLIST_ENTRY(thread_list_t) list;
568 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
570 void ast_register_thread(char *name)
572 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
577 ast_assert(multi_thread_safe);
578 new->id = pthread_self();
579 new->lwp = ast_get_tid();
580 new->name = name; /* steal the allocated memory for the thread name */
581 AST_RWLIST_WRLOCK(&thread_list);
582 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
583 AST_RWLIST_UNLOCK(&thread_list);
586 void ast_unregister_thread(void *id)
588 struct thread_list_t *x;
590 AST_RWLIST_WRLOCK(&thread_list);
591 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
592 if ((void *) x->id == id) {
593 AST_RWLIST_REMOVE_CURRENT(list);
597 AST_RWLIST_TRAVERSE_SAFE_END;
598 AST_RWLIST_UNLOCK(&thread_list);
605 /*! \brief Give an overview of core settings */
606 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
614 e->command = "core show settings";
615 e->usage = "Usage: core show settings\n"
616 " Show core misc settings";
622 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
624 ast_cli(a->fd, "\nPBX Core settings\n");
625 ast_cli(a->fd, "-----------------\n");
626 ast_cli(a->fd, " Version: %s\n", ast_get_version());
627 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
628 if (ast_option_maxcalls)
629 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", ast_option_maxcalls, ast_active_channels());
631 ast_cli(a->fd, " Maximum calls: Not set\n");
632 if (ast_option_maxfiles)
633 ast_cli(a->fd, " Maximum open file handles: %d\n", ast_option_maxfiles);
635 ast_cli(a->fd, " Maximum open file handles: Not set\n");
636 ast_cli(a->fd, " Root console verbosity: %d\n", option_verbose);
637 ast_cli(a->fd, " Current console verbosity: %d\n", ast_verb_console_get());
638 ast_cli(a->fd, " Debug level: %d\n", option_debug);
639 ast_cli(a->fd, " Maximum load average: %lf\n", ast_option_maxload);
640 #if defined(HAVE_SYSINFO)
641 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
643 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
644 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
645 ast_cli(a->fd, " Startup time: %s\n", buf);
647 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
648 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
649 ast_cli(a->fd, " Last reload time: %s\n", buf);
651 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);
652 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
653 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
654 ast_cli(a->fd, " Default language: %s\n", ast_defaultlanguage);
655 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
656 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
657 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
658 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
659 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
660 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
661 ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
663 ast_cli(a->fd, "\n* Subsystems\n");
664 ast_cli(a->fd, " -------------\n");
665 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
666 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
667 ast_cli(a->fd, " Call data records: %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
668 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
670 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
672 ast_cli(a->fd, "\n* Directories\n");
673 ast_cli(a->fd, " -------------\n");
674 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
675 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
676 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
677 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
678 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
679 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
680 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
681 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
682 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
683 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
684 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
685 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
686 ast_cli(a->fd, "\n\n");
690 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
693 struct thread_list_t *cur;
696 e->command = "core show threads";
698 "Usage: core show threads\n"
699 " List threads currently active in the system.\n";
705 AST_RWLIST_RDLOCK(&thread_list);
706 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
707 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
710 AST_RWLIST_UNLOCK(&thread_list);
711 ast_cli(a->fd, "%d threads listed.\n", count);
715 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
717 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
718 * to be based on the new swapctl(2) system call.
720 static int swapmode(int *used, int *total)
722 struct swapent *swdev;
723 int nswap, rnswap, i;
725 nswap = swapctl(SWAP_NSWAP, 0, 0);
729 swdev = ast_calloc(nswap, sizeof(*swdev));
733 rnswap = swapctl(SWAP_STATS, swdev, nswap);
739 /* if rnswap != nswap, then what? */
741 /* Total things up */
743 for (i = 0; i < nswap; i++) {
744 if (swdev[i].se_flags & SWF_ENABLE) {
745 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
746 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
752 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
753 static int swapmode(int *used, int *total)
760 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
761 /*! \brief Give an overview of system statistics */
762 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
764 uint64_t physmem, freeram;
765 uint64_t freeswap = 0;
769 #if defined(HAVE_SYSINFO)
770 struct sysinfo sys_info;
772 uptime = sys_info.uptime / 3600;
773 physmem = sys_info.totalram * sys_info.mem_unit;
774 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
775 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
776 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
777 nprocs = sys_info.procs;
778 #elif defined(HAVE_SYSCTL)
779 static int pageshift;
780 struct vmtotal vmtotal;
781 struct timeval boottime;
783 int mib[2], pagesize, usedswap = 0;
785 /* calculate the uptime by looking at boottime */
788 mib[1] = KERN_BOOTTIME;
789 len = sizeof(boottime);
790 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
791 uptime = now - boottime.tv_sec;
793 uptime = uptime/3600;
794 /* grab total physical memory */
796 #if defined(HW_PHYSMEM64)
797 mib[1] = HW_PHYSMEM64;
801 len = sizeof(physmem);
802 sysctl(mib, 2, &physmem, &len, NULL, 0);
804 pagesize = getpagesize();
806 while (pagesize > 1) {
811 /* we only need the amount of log(2)1024 for our conversion */
817 len = sizeof(vmtotal);
818 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
819 freeram = (vmtotal.t_free << pageshift);
820 /* generate swap usage and totals */
821 swapmode(&usedswap, &totalswap);
822 freeswap = (totalswap - usedswap);
823 /* grab number of processes */
824 #if defined(__OpenBSD__)
826 mib[1] = KERN_NPROCS;
827 len = sizeof(nprocs);
828 sysctl(mib, 2, &nprocs, &len, NULL, 0);
834 e->command = "core show sysinfo";
836 "Usage: core show sysinfo\n"
837 " List current system information.\n";
843 ast_cli(a->fd, "\nSystem Statistics\n");
844 ast_cli(a->fd, "-----------------\n");
845 ast_cli(a->fd, " System Uptime: %ld hours\n", uptime);
846 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
847 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
848 #if defined(HAVE_SYSINFO)
849 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
851 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
852 ast_cli(a->fd, " Total Swap Space: %d KiB\n", totalswap);
853 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
855 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
860 struct profile_entry {
862 uint64_t scale; /* if non-zero, values are scaled by this */
868 struct profile_data {
871 struct profile_entry e[0];
874 static struct profile_data *prof_data;
876 /*! \brief allocates a counter with a given name and scale.
877 * \return Returns the identifier of the counter.
879 int ast_add_profile(const char *name, uint64_t scale)
881 int l = sizeof(struct profile_data);
882 int n = 10; /* default entries */
884 if (prof_data == NULL) {
885 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
886 if (prof_data == NULL)
888 prof_data->entries = 0;
889 prof_data->max_size = n;
891 if (prof_data->entries >= prof_data->max_size) {
893 n = prof_data->max_size + 20;
894 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
898 prof_data->max_size = n;
900 n = prof_data->entries++;
901 prof_data->e[n].name = ast_strdup(name);
902 prof_data->e[n].value = 0;
903 prof_data->e[n].events = 0;
904 prof_data->e[n].mark = 0;
905 prof_data->e[n].scale = scale;
909 int64_t ast_profile(int i, int64_t delta)
911 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
913 if (prof_data->e[i].scale > 1)
914 delta /= prof_data->e[i].scale;
915 prof_data->e[i].value += delta;
916 prof_data->e[i].events++;
917 return prof_data->e[i].value;
920 /* The RDTSC instruction was introduced on the Pentium processor and is not
921 * implemented on certain clones, like the Cyrix 586. Hence, the previous
922 * expectation of __i386__ was in error. */
923 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
924 #if defined(__FreeBSD__)
925 #include <machine/cpufunc.h>
927 static __inline uint64_t
932 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
936 #else /* supply a dummy function on other platforms */
937 static __inline uint64_t
944 int64_t ast_mark(int i, int startstop)
946 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
949 prof_data->e[i].mark = rdtsc();
951 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
952 if (prof_data->e[i].scale > 1)
953 prof_data->e[i].mark /= prof_data->e[i].scale;
954 prof_data->e[i].value += prof_data->e[i].mark;
955 prof_data->e[i].events++;
957 return prof_data->e[i].mark;
960 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
961 max = prof_data->entries;\
962 if (a->argc > 3) { /* specific entries */ \
963 if (isdigit(a->argv[3][0])) { \
964 min = atoi(a->argv[3]); \
965 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
966 max = atoi(a->argv[4]); \
968 search = a->argv[3]; \
970 if (max > prof_data->entries) \
971 max = prof_data->entries;
973 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
976 const char *search = NULL;
979 e->command = "core show profile";
980 e->usage = "Usage: core show profile\n"
981 " show profile information";
987 if (prof_data == NULL)
990 DEFINE_PROFILE_MIN_MAX_VALUES;
991 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
992 prof_data->entries, prof_data->max_size);
993 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
994 "Value", "Average", "Name");
995 for (i = min; i < max; i++) {
996 struct profile_entry *entry = &prof_data->e[i];
997 if (!search || strstr(entry->name, search))
998 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
1001 (long)entry->events, (long long)entry->value,
1002 (long long)(entry->events ? entry->value / entry->events : entry->value),
1008 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1011 const char *search = NULL;
1014 e->command = "core clear profile";
1015 e->usage = "Usage: core clear profile\n"
1016 " clear profile information";
1022 if (prof_data == NULL)
1025 DEFINE_PROFILE_MIN_MAX_VALUES;
1026 for (i= min; i < max; i++) {
1027 if (!search || strstr(prof_data->e[i].name, search)) {
1028 prof_data->e[i].value = 0;
1029 prof_data->e[i].events = 0;
1034 #undef DEFINE_PROFILE_MIN_MAX_VALUES
1036 /*! \brief CLI command to list module versions */
1037 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1039 #define FORMAT "%-25.25s %-40.40s\n"
1040 struct file_version *iterator;
1042 int havepattern = 0;
1044 int count_files = 0;
1046 int matchlen, which = 0;
1047 struct file_version *find;
1051 e->command = "core show file version [like]";
1053 "Usage: core show file version [like <pattern>]\n"
1054 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
1055 " Optional regular expression pattern is used to filter the file list.\n";
1058 matchlen = strlen(a->word);
1061 AST_RWLIST_RDLOCK(&file_versions);
1062 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
1063 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
1064 ret = ast_strdup(find->file);
1068 AST_RWLIST_UNLOCK(&file_versions);
1075 if (!strcasecmp(a->argv[4], "like")) {
1076 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
1077 return CLI_SHOWUSAGE;
1080 return CLI_SHOWUSAGE;
1088 return CLI_SHOWUSAGE;
1091 ast_cli(a->fd, FORMAT, "File", "Revision");
1092 ast_cli(a->fd, FORMAT, "----", "--------");
1093 AST_RWLIST_RDLOCK(&file_versions);
1094 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
1095 if (havename && strcasecmp(iterator->file, a->argv[4]))
1098 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
1101 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
1106 AST_RWLIST_UNLOCK(&file_versions);
1108 ast_cli(a->fd, "%d files listed.\n", count_files);
1118 #endif /* ! LOW_MEMORY */
1120 static void publish_fully_booted(void)
1122 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1124 json_object = ast_json_pack("{s: s}",
1125 "Status", "Fully Booted");
1126 ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
1129 static void ast_run_atexits(int run_cleanups)
1131 struct ast_atexit *ae;
1133 AST_LIST_LOCK(&atexits);
1134 while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1135 if (ae->func && (!ae->is_cleanup || run_cleanups)) {
1140 AST_LIST_UNLOCK(&atexits);
1143 static void __ast_unregister_atexit(void (*func)(void))
1145 struct ast_atexit *ae;
1147 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1148 if (ae->func == func) {
1149 AST_LIST_REMOVE_CURRENT(list);
1154 AST_LIST_TRAVERSE_SAFE_END;
1157 static int register_atexit(void (*func)(void), int is_cleanup)
1159 struct ast_atexit *ae;
1161 ae = ast_calloc(1, sizeof(*ae));
1166 ae->is_cleanup = is_cleanup;
1168 AST_LIST_LOCK(&atexits);
1169 __ast_unregister_atexit(func);
1170 AST_LIST_INSERT_HEAD(&atexits, ae, list);
1171 AST_LIST_UNLOCK(&atexits);
1176 int ast_register_atexit(void (*func)(void))
1178 return register_atexit(func, 0);
1181 int ast_register_cleanup(void (*func)(void))
1183 return register_atexit(func, 1);
1186 void ast_unregister_atexit(void (*func)(void))
1188 AST_LIST_LOCK(&atexits);
1189 __ast_unregister_atexit(func);
1190 AST_LIST_UNLOCK(&atexits);
1193 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1194 static int fdsend(int fd, const char *s)
1196 return write(fd, s, strlen(s) + 1);
1199 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1200 static int fdprint(int fd, const char *s)
1202 return write(fd, s, strlen(s));
1205 /*! \brief NULL handler so we can collect the child exit status */
1206 static void _null_sig_handler(int sig)
1210 static struct sigaction null_sig_handler = {
1211 .sa_handler = _null_sig_handler,
1212 .sa_flags = SA_RESTART,
1215 static struct sigaction ignore_sig_handler = {
1216 .sa_handler = SIG_IGN,
1219 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1220 /*! \brief Keep track of how many threads are currently trying to wait*() on
1223 static unsigned int safe_system_level = 0;
1224 static struct sigaction safe_system_prev_handler;
1226 void ast_replace_sigchld(void)
1230 ast_mutex_lock(&safe_system_lock);
1231 level = safe_system_level++;
1233 /* only replace the handler if it has not already been done */
1235 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1238 ast_mutex_unlock(&safe_system_lock);
1241 void ast_unreplace_sigchld(void)
1245 ast_mutex_lock(&safe_system_lock);
1246 level = --safe_system_level;
1248 /* only restore the handler if we are the last one */
1250 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1253 ast_mutex_unlock(&safe_system_lock);
1256 int ast_safe_system(const char *s)
1262 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1263 ast_replace_sigchld();
1265 #ifdef HAVE_WORKING_FORK
1273 cap_t cap = cap_from_text("cap_net_admin-eip");
1275 if (cap_set_proc(cap)) {
1276 /* Careful with order! Logging cannot happen after we close FDs */
1277 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1281 #ifdef HAVE_WORKING_FORK
1282 if (ast_opt_high_priority)
1283 ast_set_priority(0);
1284 /* Close file descriptors and launch system command */
1285 ast_close_fds_above_n(STDERR_FILENO);
1287 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1289 } else if (pid > 0) {
1291 res = waitpid(pid, &status, 0);
1293 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1295 } else if (errno != EINTR)
1299 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1303 ast_unreplace_sigchld();
1304 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1312 * \brief enable or disable a logging level to a specified console
1314 void ast_console_toggle_loglevel(int fd, int level, int state)
1318 if (level >= NUMLOGLEVELS) {
1319 level = NUMLOGLEVELS - 1;
1322 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1323 if (fd == consoles[x].fd) {
1325 * Since the logging occurs when levels are false, set to
1326 * flipped iinput because this function accepts 0 as off and 1 as on
1328 consoles[x].levels[level] = state ? 0 : 1;
1335 * \brief mute or unmute a console from logging
1337 void ast_console_toggle_mute(int fd, int silent)
1340 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1341 if (fd == consoles[x].fd) {
1342 if (consoles[x].mute) {
1343 consoles[x].mute = 0;
1345 ast_cli(fd, "Console is not muted anymore.\n");
1347 consoles[x].mute = 1;
1349 ast_cli(fd, "Console is muted.\n");
1354 ast_cli(fd, "Couldn't find remote console.\n");
1358 * \brief log the string to all attached network console clients
1360 static void ast_network_puts_mutable(const char *string, int level)
1364 for (x = 0; x < AST_MAX_CONNECTS; ++x) {
1365 if (consoles[x].fd < 0
1367 || consoles[x].levels[level]) {
1370 fdprint(consoles[x].p[1], string);
1375 * \brief log the string to the root console, and all attached
1376 * network console clients
1378 void ast_console_puts_mutable(const char *string, int level)
1380 /* Send to the root console */
1381 fputs(string, stdout);
1384 /* Send to any network console clients */
1385 ast_network_puts_mutable(string, level);
1389 * \brief write the string to all attached console clients
1391 static void ast_network_puts(const char *string)
1395 for (x = 0; x < AST_MAX_CONNECTS; ++x) {
1396 if (consoles[x].fd < 0) {
1399 fdprint(consoles[x].p[1], string);
1404 * \brief write the string to the root console, and all attached
1405 * network console clients
1407 void ast_console_puts(const char *string)
1409 /* Send to the root console */
1410 fputs(string, stdout);
1413 /* Send to any network console clients */
1414 ast_network_puts(string);
1417 static void network_verboser(const char *string)
1422 /* Send to any network console clients if client verbocity allows. */
1423 verb_level = VERBOSE_MAGIC2LEVEL(string);
1424 for (x = 0; x < AST_MAX_CONNECTS; ++x) {
1425 if (consoles[x].fd < 0
1427 || consoles[x].levels[__LOG_VERBOSE]
1428 || consoles[x].option_verbose < verb_level) {
1431 fdprint(consoles[x].p[1], string);
1435 static pthread_t lthread;
1438 * \brief read() function supporting the reception of user credentials.
1440 * \param fd Socket file descriptor.
1441 * \param buffer Receive buffer.
1442 * \param size 'buffer' size.
1443 * \param con Console structure to set received credentials
1444 * \retval -1 on error
1445 * \retval the number of bytes received on success.
1447 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1449 #if defined(SO_PEERCRED)
1450 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1451 #define HAVE_STRUCT_UCRED_UID
1452 struct sockpeercred cred;
1456 socklen_t len = sizeof(cred);
1458 #if defined(HAVE_GETPEEREID)
1466 result = read(fd, buffer, size);
1471 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1472 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1475 #if defined(HAVE_STRUCT_UCRED_UID)
1478 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1481 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1483 #elif defined(HAVE_GETPEEREID)
1484 if (getpeereid(fd, &uid, &gid)) {
1496 /* This is the thread running the remote console on the main process. */
1497 static void *netconsole(void *vconsole)
1499 struct console *con = vconsole;
1500 char hostname[MAXHOSTNAMELEN] = "";
1503 const char * const end_buf = inbuf + sizeof(inbuf);
1504 char *start_read = inbuf;
1506 struct pollfd fds[2];
1508 if (gethostname(hostname, sizeof(hostname)-1))
1509 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1510 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1511 fdprint(con->fd, outbuf);
1512 ast_verb_console_register(&con->option_verbose);
1514 fds[0].fd = con->fd;
1515 fds[0].events = POLLIN;
1517 fds[1].fd = con->p[0];
1518 fds[1].events = POLLIN;
1521 res = ast_poll(fds, 2, -1);
1524 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1527 if (fds[0].revents) {
1528 int cmds_read, bytes_read;
1529 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1532 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1533 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1534 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1537 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1538 * NULL and not trailing partial commands. */
1539 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1540 /* No commands were read. We either have a short read on the first command
1541 * with space left, or a command that is too long */
1542 if (start_read + bytes_read < end_buf) {
1543 start_read += bytes_read;
1545 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1550 if (start_read[bytes_read - 1] == '\0') {
1551 /* The read ended on a command boundary, start reading again at the head of inbuf */
1555 /* If we get this far, we have left over characters that have not been processed.
1556 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1557 * We are guaranteed to have at least cmds_read NULLs */
1558 while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1561 memmove(inbuf, start_read, end_buf - start_read);
1562 start_read = end_buf - start_read + inbuf;
1564 if (fds[1].revents) {
1565 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1567 ast_log(LOG_ERROR, "read returned %d\n", res);
1570 res = write(con->fd, outbuf, res);
1575 ast_verb_console_unregister();
1576 if (!ast_opt_hide_connect) {
1577 ast_verb(3, "Remote UNIX connection disconnected\n");
1587 static void *listener(void *unused)
1589 struct sockaddr_un sunaddr;
1594 struct pollfd fds[1];
1598 fds[0].fd = ast_socket;
1599 fds[0].events = POLLIN;
1600 s = ast_poll(fds, 1, -1);
1601 pthread_testcancel();
1604 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1607 len = sizeof(sunaddr);
1608 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1611 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1613 #if !defined(SO_PASSCRED)
1617 /* turn on socket credentials passing. */
1618 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1619 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1622 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1623 if (consoles[x].fd >= 0) {
1626 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1627 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1628 fdprint(s, "Server failed to create pipe\n");
1632 flags = fcntl(consoles[x].p[1], F_GETFL);
1633 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1634 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1635 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1636 to know if the user didn't send the credentials. */
1637 consoles[x].uid = -2;
1638 consoles[x].gid = -2;
1639 /* Server default of remote console verbosity level is OFF. */
1640 consoles[x].option_verbose = 0;
1642 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1643 consoles[x].fd = -1;
1644 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1645 close(consoles[x].p[0]);
1646 close(consoles[x].p[1]);
1647 fdprint(s, "Server failed to spawn thread\n");
1652 if (x >= AST_MAX_CONNECTS) {
1653 fdprint(s, "No more connections allowed\n");
1654 ast_log(LOG_WARNING, "No more connections allowed\n");
1656 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1657 ast_verb(3, "Remote UNIX connection\n");
1665 static int ast_makesocket(void)
1667 struct sockaddr_un sunaddr;
1673 for (x = 0; x < AST_MAX_CONNECTS; x++)
1674 consoles[x].fd = -1;
1675 unlink(ast_config_AST_SOCKET);
1676 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1677 if (ast_socket < 0) {
1678 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1681 memset(&sunaddr, 0, sizeof(sunaddr));
1682 sunaddr.sun_family = AF_LOCAL;
1683 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1684 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1686 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1691 res = listen(ast_socket, 2);
1693 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1698 if (ast_register_verbose(network_verboser)) {
1699 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1702 if (ast_pthread_create_background(<hread, NULL, listener, NULL)) {
1703 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1708 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1710 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1711 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1716 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1718 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1719 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1724 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1725 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1727 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1730 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1732 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1733 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1739 static int ast_tryconnect(void)
1741 struct sockaddr_un sunaddr;
1743 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1744 if (ast_consock < 0) {
1745 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1748 memset(&sunaddr, 0, sizeof(sunaddr));
1749 sunaddr.sun_family = AF_LOCAL;
1750 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1751 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1760 /*! \brief Urgent handler
1762 * Called by soft_hangup to interrupt the poll, read, or other
1763 * system call. We don't actually need to do anything though.
1764 * Remember: Cannot EVER ast_log from within a signal handler
1766 static void _urg_handler(int num)
1771 static struct sigaction urg_handler = {
1772 .sa_handler = _urg_handler,
1773 .sa_flags = SA_RESTART,
1776 static void _hup_handler(int num)
1778 int a = 0, save_errno = errno;
1779 printf("Received HUP signal -- Reloading configs\n");
1781 execvp(_argv[0], _argv);
1782 sig_flags.need_reload = 1;
1783 if (sig_alert_pipe[1] != -1) {
1784 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1785 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1791 static struct sigaction hup_handler = {
1792 .sa_handler = _hup_handler,
1793 .sa_flags = SA_RESTART,
1796 static void _child_handler(int sig)
1798 /* Must not ever ast_log or ast_verbose within signal handler */
1799 int n, status, save_errno = errno;
1802 * Reap all dead children -- not just one
1804 for (n = 0; waitpid(-1, &status, WNOHANG) > 0; n++)
1806 if (n == 0 && option_debug)
1807 printf("Huh? Child handler, but nobody there?\n");
1811 static struct sigaction child_handler = {
1812 .sa_handler = _child_handler,
1813 .sa_flags = SA_RESTART,
1816 /*! \brief Set maximum open files */
1817 static void set_ulimit(int value)
1819 struct rlimit l = {0, 0};
1822 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1829 if (setrlimit(RLIMIT_NOFILE, &l)) {
1830 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1834 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1839 /*! \brief Set an X-term or screen title */
1840 static void set_title(char *text)
1842 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1843 fprintf(stdout, "\033]2;%s\007", text);
1846 static void set_icon(char *text)
1848 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1849 fprintf(stdout, "\033]1;%s\007", text);
1852 /*! \brief We set ourselves to a high priority, that we might pre-empt
1853 * everything else. If your PBX has heavy activity on it, this is a
1856 int ast_set_priority(int pri)
1858 struct sched_param sched;
1859 memset(&sched, 0, sizeof(sched));
1862 sched.sched_priority = 10;
1863 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1864 ast_log(LOG_WARNING, "Unable to set high priority\n");
1867 ast_verb(1, "Set to realtime thread\n");
1869 sched.sched_priority = 0;
1870 /* According to the manpage, these parameters can never fail. */
1871 sched_setscheduler(0, SCHED_OTHER, &sched);
1875 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1876 ast_log(LOG_WARNING, "Unable to set high priority\n");
1879 ast_verb(1, "Set to high priority\n");
1881 /* According to the manpage, these parameters can never fail. */
1882 setpriority(PRIO_PROCESS, 0, 0);
1888 int ast_shutdown_final(void)
1890 return shuttingdown == SHUTTING_DOWN_FINAL;
1893 int ast_shutting_down(void)
1895 return shutdown_pending;
1898 int ast_cancel_shutdown(void)
1900 int shutdown_aborted = 0;
1902 ast_mutex_lock(&safe_system_lock);
1903 if (shuttingdown >= SHUTDOWN_FAST) {
1904 shuttingdown = NOT_SHUTTING_DOWN;
1905 shutdown_pending = 0;
1906 shutdown_aborted = 1;
1908 ast_mutex_unlock(&safe_system_lock);
1909 return shutdown_aborted;
1914 * \brief Initiate system shutdown -- prevents new channels from being allocated.
1916 static void ast_begin_shutdown(void)
1918 ast_mutex_lock(&safe_system_lock);
1919 if (shuttingdown != NOT_SHUTTING_DOWN) {
1920 shutdown_pending = 1;
1922 ast_mutex_unlock(&safe_system_lock);
1925 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1926 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1928 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1930 if (can_safely_quit(niceness, restart)) {
1931 really_quit(num, niceness, restart);
1932 /* No one gets here. */
1934 /* It wasn't our time. */
1937 #define SHUTDOWN_TIMEOUT 15 /* Seconds */
1941 * \brief Wait for all channels to die, a timeout, or shutdown cancelled.
1944 * \param niceness Shutdown niceness in effect
1945 * \param seconds Number of seconds to wait or less than zero if indefinitely.
1947 * \retval zero if waiting wasn't necessary. We were idle.
1948 * \retval non-zero if we had to wait.
1950 static int wait_for_channels_to_die(shutdown_nice_t niceness, int seconds)
1958 if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1962 /* No timeout so just poll every second */
1967 /* Wait up to the given seconds for all channels to go away */
1968 if (seconds < (now - start)) {
1972 /* Sleep 1/10 of a second */
1980 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1984 /* Check if someone else isn't already doing this. */
1985 ast_mutex_lock(&safe_system_lock);
1986 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1987 /* Already in progress and other request was less nice. */
1988 ast_mutex_unlock(&safe_system_lock);
1989 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1992 shuttingdown = niceness;
1993 ast_mutex_unlock(&safe_system_lock);
1995 /* Try to get as many CDRs as possible submitted to the backend engines
1996 * (if in batch mode). really_quit happens to call it again when running
1997 * the atexit handlers, otherwise this would be a bit early. */
1998 ast_cdr_engine_term();
2001 * Shutdown the message queue for the technology agnostic message channel.
2002 * This has to occur before we pause shutdown pending ast_undestroyed_channels.
2004 * XXX This is not reversed on shutdown cancel.
2008 if (niceness == SHUTDOWN_NORMAL) {
2009 /* Begin shutdown routine, hanging up active channels */
2010 ast_begin_shutdown();
2011 if (ast_opt_console) {
2012 ast_verb(0, "Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
2014 ast_softhangup_all();
2015 waited |= wait_for_channels_to_die(niceness, SHUTDOWN_TIMEOUT);
2016 } else if (niceness >= SHUTDOWN_NICE) {
2017 if (niceness != SHUTDOWN_REALLY_NICE) {
2018 ast_begin_shutdown();
2020 if (ast_opt_console) {
2021 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
2023 waited |= wait_for_channels_to_die(niceness, -1);
2026 /* Re-acquire lock and check if someone changed the niceness, in which
2027 * case someone else has taken over the shutdown.
2029 ast_mutex_lock(&safe_system_lock);
2030 if (shuttingdown != niceness) {
2031 if (shuttingdown == NOT_SHUTTING_DOWN && ast_opt_console) {
2032 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
2034 ast_mutex_unlock(&safe_system_lock);
2038 if (niceness >= SHUTDOWN_REALLY_NICE) {
2039 shuttingdown = SHUTTING_DOWN;
2040 ast_mutex_unlock(&safe_system_lock);
2042 /* No more Mr. Nice guy. We are committed to shutting down now. */
2043 ast_begin_shutdown();
2044 ast_softhangup_all();
2045 waited |= wait_for_channels_to_die(SHUTTING_DOWN, SHUTDOWN_TIMEOUT);
2047 ast_mutex_lock(&safe_system_lock);
2049 shuttingdown = SHUTTING_DOWN_FINAL;
2050 ast_mutex_unlock(&safe_system_lock);
2052 if (niceness >= SHUTDOWN_NORMAL && waited) {
2054 * We were not idle. Give things in progress a chance to
2055 * recognize the final shutdown phase.
2062 /*! Called when exiting is certain. */
2063 static void really_quit(int num, shutdown_nice_t niceness, int restart)
2065 int active_channels;
2066 struct ast_json *json_object = NULL;
2067 int run_cleanups = niceness >= SHUTDOWN_NICE;
2070 ast_module_shutdown();
2073 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
2074 char filename[80] = "";
2075 if (getenv("HOME")) {
2076 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2078 if (!ast_strlen_zero(filename)) {
2079 ast_el_write_history(filename);
2081 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
2082 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
2086 if (el_hist != NULL) {
2087 history_end(el_hist);
2089 } else if (mon_sig_flags == pthread_self()) {
2090 if (consolethread != AST_PTHREADT_NULL) {
2091 pthread_kill(consolethread, SIGURG);
2095 active_channels = ast_active_channels();
2096 /* Don't publish messages if we're a remote console - we won't have all of the Stasis
2097 * topics or message types
2099 if (!ast_opt_remote) {
2100 json_object = ast_json_pack("{s: s, s: s}",
2101 "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
2102 "Restart", restart ? "True" : "False");
2103 ast_manager_publish_event("Shutdown", EVENT_FLAG_SYSTEM, json_object);
2104 ast_json_unref(json_object);
2107 ast_verb(0, "Asterisk %s ending (%d).\n",
2108 active_channels ? "uncleanly" : "cleanly", num);
2110 ast_verb(0, "Executing last minute cleanups\n");
2111 ast_run_atexits(run_cleanups);
2113 ast_debug(1, "Asterisk ending (%d).\n", num);
2114 if (ast_socket > -1) {
2115 pthread_cancel(lthread);
2118 unlink(ast_config_AST_SOCKET);
2119 pthread_kill(lthread, SIGURG);
2120 pthread_join(lthread, NULL);
2122 if (ast_consock > -1)
2124 if (!ast_opt_remote)
2125 unlink(ast_config_AST_PID);
2126 if (sig_alert_pipe[0])
2127 close(sig_alert_pipe[0]);
2128 if (sig_alert_pipe[1])
2129 close(sig_alert_pipe[1]);
2130 printf("%s", term_quit());
2133 ast_verb(0, "Preparing for Asterisk restart...\n");
2134 /* Mark all FD's for closing on exec */
2135 for (i = 3; i < 32768; i++) {
2136 fcntl(i, F_SETFD, FD_CLOEXEC);
2138 ast_verb(0, "Asterisk is now restarting...\n");
2145 /* If there is a consolethread running send it a SIGHUP
2146 so it can execvp, otherwise we can do it ourselves */
2147 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
2148 pthread_kill(consolethread, SIGHUP);
2149 /* Give the signal handler some time to complete */
2152 execvp(_argv[0], _argv);
2163 static void __quit_handler(int num)
2166 sig_flags.need_quit = 1;
2167 if (sig_alert_pipe[1] != -1) {
2168 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
2169 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
2172 /* There is no need to restore the signal handler here, since the app
2173 * is going to exit */
2176 static void __remote_quit_handler(int num)
2178 sig_flags.need_quit = 1;
2181 static void set_header(char *outbuf, int maxout, char level)
2189 case 1: cmp = VERBOSE_PREFIX_1;
2191 case 2: cmp = VERBOSE_PREFIX_2;
2193 case 3: cmp = VERBOSE_PREFIX_3;
2195 default: cmp = VERBOSE_PREFIX_4;
2199 if (ast_opt_timestamp) {
2201 struct timeval now = ast_tvnow();
2202 ast_localtime(&now, &tm, NULL);
2203 ast_strftime(date, sizeof(date), ast_logger_get_dateformat(), &tm);
2206 snprintf(outbuf, maxout, "%s%s%s%s%s%s",
2207 ast_opt_timestamp ? "[" : "",
2208 ast_opt_timestamp ? date : "",
2209 ast_opt_timestamp ? "] " : "",
2210 cmp ? ast_term_color(COLOR_GRAY, 0) : "",
2212 cmp ? ast_term_reset() : "");
2215 struct console_state_data {
2216 char verbose_line_level;
2219 static int console_state_init(void *ptr)
2221 struct console_state_data *state = ptr;
2222 state->verbose_line_level = 0;
2226 AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr);
2228 static int console_print(const char *s, int local)
2230 struct console_state_data *state =
2231 ast_threadstorage_get(&console_state, sizeof(*state));
2236 unsigned int newline;
2239 if (VERBOSE_HASMAGIC(s)) {
2241 /* always use the given line's level, otherwise
2242 we'll use the last line's level */
2243 state->verbose_line_level = VERBOSE_MAGIC2LEVEL(s);
2245 /* move past magic */
2248 set_header(prefix, sizeof(prefix), state->verbose_line_level);
2254 /* for a given line separate on verbose magic, newline, and eol */
2255 if ((s = strchr(c, '\n'))) {
2259 s = strchr(c, '\0');
2263 /* check if we should write this line after calculating begin/end
2264 so we process the case of a higher level line embedded within
2265 two lower level lines */
2266 if (state->verbose_line_level > option_verbose) {
2270 if (!ast_strlen_zero(prefix)) {
2271 fputs(prefix, stdout);
2275 if (fwrite(c, sizeof(char), num, stdout) < num) {
2280 /* if at least some info has been written
2281 we'll want to return true */
2287 /* if ending on a newline then reset last level to zero
2288 since what follows may be not be logging output */
2289 state->verbose_line_level = 0;
2299 static void console_verboser(const char *s)
2301 if (!console_print(s, 1)) {
2305 /* Wake up a poll()ing console */
2306 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2307 pthread_kill(consolethread, SIGURG);
2311 static int ast_all_zeros(char *s)
2321 /* This is the main console CLI command handler. Run by the main() thread. */
2322 static void consolehandler(char *s)
2324 printf("%s", term_end());
2327 /* Called when readline data is available */
2328 if (!ast_all_zeros(s))
2329 ast_el_add_history(s);
2330 /* The real handler for bang */
2333 ast_safe_system(s+1);
2335 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2337 ast_cli_command(STDOUT_FILENO, s);
2340 static int remoteconsolehandler(char *s)
2344 /* Called when readline data is available */
2345 if (!ast_all_zeros(s))
2346 ast_el_add_history(s);
2348 while (isspace(*s)) {
2352 /* The real handler for bang */
2355 ast_safe_system(s+1);
2357 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2359 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2360 (s[4] == '\0' || isspace(s[4]))) {
2361 quit_handler(0, SHUTDOWN_FAST, 0);
2364 char *shrunk = ast_strdupa(s);
2369 * Remove duplicate spaces from shrunk for matching purposes.
2371 * shrunk has at least one character in it to start with or we
2372 * couldn't get here.
2374 for (prev = shrunk, cur = shrunk + 1; *cur; ++cur) {
2375 if (*prev == ' ' && *cur == ' ') {
2376 /* Skip repeated space delimiter. */
2383 if (strncasecmp(shrunk, "core set verbose ", 17) == 0) {
2385 * We need to still set the rasterisk option_verbose in case we are
2386 * talking to an earlier version which doesn't prefilter verbose
2387 * levels. This is really a compromise as we should always take
2388 * whatever the server sends.
2391 if (!strncasecmp(shrunk + 17, "off", 3)) {
2392 ast_verb_console_set(0);
2398 if (strncasecmp(shrunk + 17, "atleast ", atleast)) {
2402 if (sscanf(shrunk + 17 + atleast, "%30d", &verbose_new) == 1) {
2403 if (!atleast || ast_verb_console_get() < verbose_new) {
2404 ast_verb_console_set(verbose_new);
2414 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2418 e->command = "core show version";
2420 "Usage: core show version\n"
2421 " Shows Asterisk version information.\n";
2428 return CLI_SHOWUSAGE;
2429 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2430 ast_get_version(), ast_build_user, ast_build_hostname,
2431 ast_build_machine, ast_build_os, ast_build_date);
2436 static int handle_quit(int fd, int argc, char *argv[])
2439 return RESULT_SHOWUSAGE;
2440 quit_handler(0, SHUTDOWN_NORMAL, 0);
2441 return RESULT_SUCCESS;
2445 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2449 e->command = "core stop now";
2451 "Usage: core stop now\n"
2452 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2458 if (a->argc != e->args)
2459 return CLI_SHOWUSAGE;
2460 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2464 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2468 e->command = "core stop gracefully";
2470 "Usage: core stop gracefully\n"
2471 " Causes Asterisk to not accept new calls, and exit when all\n"
2472 " active calls have terminated normally.\n";
2478 if (a->argc != e->args)
2479 return CLI_SHOWUSAGE;
2480 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2484 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2488 e->command = "core stop when convenient";
2490 "Usage: core stop when convenient\n"
2491 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2497 if (a->argc != e->args)
2498 return CLI_SHOWUSAGE;
2499 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2500 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2504 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2508 e->command = "core restart now";
2510 "Usage: core restart now\n"
2511 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2518 if (a->argc != e->args)
2519 return CLI_SHOWUSAGE;
2520 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2524 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2528 e->command = "core restart gracefully";
2530 "Usage: core restart gracefully\n"
2531 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2532 " restart when all active calls have ended.\n";
2538 if (a->argc != e->args)
2539 return CLI_SHOWUSAGE;
2540 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2544 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2548 e->command = "core restart when convenient";
2550 "Usage: core restart when convenient\n"
2551 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2557 if (a->argc != e->args)
2558 return CLI_SHOWUSAGE;
2559 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2560 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2564 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2568 e->command = "core abort shutdown";
2570 "Usage: core abort shutdown\n"
2571 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2572 " call operations.\n";
2578 if (a->argc != e->args)
2579 return CLI_SHOWUSAGE;
2581 ast_cancel_shutdown();
2586 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2592 "Usage: !<command>\n"
2593 " Executes a given shell command\n";
2601 static const char warranty_lines[] = {
2605 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2606 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2607 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2608 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2609 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2610 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2611 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2612 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2613 "REPAIR OR CORRECTION.\n"
2615 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2616 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2617 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2618 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2619 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2620 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2621 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2622 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2623 "POSSIBILITY OF SUCH DAMAGES.\n"
2626 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2630 e->command = "core show warranty";
2632 "Usage: core show warranty\n"
2633 " Shows the warranty (if any) for this copy of Asterisk.\n";
2639 ast_cli(a->fd, "%s", warranty_lines);
2644 static const char license_lines[] = {
2646 "This program is free software; you can redistribute it and/or modify\n"
2647 "it under the terms of the GNU General Public License version 2 as\n"
2648 "published by the Free Software Foundation.\n"
2650 "This program also contains components licensed under other licenses.\n"
2653 "This program is distributed in the hope that it will be useful,\n"
2654 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2655 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2656 "GNU General Public License for more details.\n"
2658 "You should have received a copy of the GNU General Public License\n"
2659 "along with this program; if not, write to the Free Software\n"
2660 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2663 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2667 e->command = "core show license";
2669 "Usage: core show license\n"
2670 " Shows the license(s) for this copy of Asterisk.\n";
2676 ast_cli(a->fd, "%s", license_lines);
2681 #define ASTERISK_PROMPT "*CLI> "
2684 * \brief Shutdown Asterisk CLI commands.
2686 * \note These CLI commands cannot be unregistered at shutdown
2687 * because one of them is likely the reason for the shutdown.
2688 * The CLI generates a warning if a command is in-use when it is
2691 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2692 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2693 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2694 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2695 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2696 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2697 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2700 static struct ast_cli_entry cli_asterisk[] = {
2701 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2702 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2703 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2704 AST_CLI_DEFINE(handle_version, "Display version info"),
2705 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2706 #if !defined(LOW_MEMORY)
2707 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2708 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2709 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2710 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2712 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2713 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2714 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2715 #endif /* ! LOW_MEMORY */
2718 static void send_rasterisk_connect_commands(void)
2723 * Tell the server asterisk instance about the verbose level
2724 * initially desired.
2726 if (option_verbose) {
2727 snprintf(buf, sizeof(buf), "core set verbose atleast %d silent", option_verbose);
2728 fdsend(ast_consock, buf);
2732 snprintf(buf, sizeof(buf), "core set debug atleast %d", option_debug);
2733 fdsend(ast_consock, buf);
2736 if (!ast_opt_mute) {
2737 fdsend(ast_consock, "logger mute silent");
2739 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2743 static int ast_el_read_char(EditLine *editline, char *cp)
2747 struct pollfd fds[2];
2750 #define EL_BUF_SIZE 512
2751 char buf[EL_BUF_SIZE];
2755 fds[0].fd = ast_consock;
2756 fds[0].events = POLLIN;
2757 if (!ast_opt_exec) {
2758 fds[1].fd = STDIN_FILENO;
2759 fds[1].events = POLLIN;
2762 res = ast_poll(fds, max, -1);
2764 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2768 fprintf(stderr, "poll failed: %s\n", strerror(errno));
2772 if (!ast_opt_exec && fds[1].revents) {
2773 num_read = read(STDIN_FILENO, cp, 1);
2780 if (fds[0].revents) {
2781 res = read(ast_consock, buf, sizeof(buf) - 1);
2782 /* if the remote side disappears exit */
2784 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2785 if (!ast_opt_reconnect) {
2786 quit_handler(0, SHUTDOWN_FAST, 0);
2789 int reconnects_per_second = 20;
2790 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2791 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2792 if (ast_tryconnect()) {
2793 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2794 printf("%s", term_quit());
2796 send_rasterisk_connect_commands();
2799 usleep(1000000 / reconnects_per_second);
2801 if (tries >= 30 * reconnects_per_second) {
2802 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2803 quit_handler(0, SHUTDOWN_FAST, 0);
2811 /* Write over the CLI prompt */
2812 if (!ast_opt_exec && !lastpos) {
2813 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2817 console_print(buf, 0);
2819 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2831 static struct ast_str *prompt = NULL;
2833 static char *cli_prompt(EditLine *editline)
2838 static int cli_prompt_changes = 0;
2842 if (prompt == NULL) {
2843 prompt = ast_str_create(100);
2844 } else if (!cli_prompt_changes) {
2845 return ast_str_buffer(prompt);
2847 ast_str_reset(prompt);
2850 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2852 struct timeval ts = ast_tvnow();
2853 while (*t != '\0') {
2855 char hostname[MAXHOSTNAMELEN] = "";
2857 struct ast_tm tm = { 0, };
2858 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2862 case 'C': /* color */
2864 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2865 ast_term_color_code(&prompt, fgcolor, bgcolor);
2867 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2868 ast_term_color_code(&prompt, fgcolor, 0);
2872 /* If the color has been reset correctly, then there's no need to reset it later */
2873 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2875 case 'd': /* date */
2876 if (ast_localtime(&ts, &tm, NULL)) {
2877 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2878 ast_str_append(&prompt, 0, "%s", tmp);
2879 cli_prompt_changes++;
2882 case 'g': /* group */
2883 if ((gr = getgrgid(getgid()))) {
2884 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2887 case 'h': /* hostname */
2888 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2889 ast_str_append(&prompt, 0, "%s", hostname);
2891 ast_str_append(&prompt, 0, "%s", "localhost");
2894 case 'H': /* short hostname */
2895 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2897 if ((dotptr = strchr(hostname, '.'))) {
2900 ast_str_append(&prompt, 0, "%s", hostname);
2902 ast_str_append(&prompt, 0, "%s", "localhost");
2905 #ifdef HAVE_GETLOADAVG
2906 case 'l': /* load avg */
2908 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2910 getloadavg(list, 3);
2911 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2912 cli_prompt_changes++;
2916 case 's': /* Asterisk system name (from asterisk.conf) */
2917 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2919 case 't': /* time */
2920 if (ast_localtime(&ts, &tm, NULL)) {
2921 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2922 ast_str_append(&prompt, 0, "%s", tmp);
2923 cli_prompt_changes++;
2926 case 'u': /* username */
2927 if ((pw = getpwuid(getuid()))) {
2928 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2931 case '#': /* process console or remote? */
2932 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2934 case '%': /* literal % */
2935 ast_str_append(&prompt, 0, "%c", '%');
2937 case '\0': /* % is last character - prevent bug */
2942 ast_str_append(&prompt, 0, "%c", *t);
2947 /* Force colors back to normal at end */
2948 ast_term_color_code(&prompt, 0, 0);
2951 ast_str_set(&prompt, 0, "%s%s",
2952 remotehostname ? remotehostname : "",
2956 return ast_str_buffer(prompt);
2959 static void destroy_match_list(char **match_list, int matches)
2964 for (idx = 0; idx < matches; ++idx) {
2965 ast_free(match_list[idx]);
2967 ast_free(match_list);
2971 static char **ast_el_strtoarr(char *buf)
2974 char **match_list = NULL;
2976 size_t match_list_len = 1;
2979 while ((retstr = strsep(&buf, " "))) {
2980 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) {
2983 if (matches + 1 >= match_list_len) {
2984 match_list_len <<= 1;
2985 new_list = ast_realloc(match_list, match_list_len * sizeof(char *));
2987 destroy_match_list(match_list, matches);
2990 match_list = new_list;
2993 retstr = ast_strdup(retstr);
2995 destroy_match_list(match_list, matches);
2998 match_list[matches++] = retstr;
3005 if (matches >= match_list_len) {
3006 new_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *));
3008 destroy_match_list(match_list, matches);
3011 match_list = new_list;
3014 match_list[matches] = NULL;
3019 static int ast_el_sort_compare(const void *i1, const void *i2)
3023 s1 = ((char **)i1)[0];
3024 s2 = ((char **)i2)[0];
3026 return strcasecmp(s1, s2);
3029 static int ast_cli_display_match_list(char **matches, int len, int max)
3031 int i, idx, limit, count;
3032 int screenwidth = 0;
3033 int numoutput = 0, numoutputline = 0;
3035 screenwidth = ast_get_termcols(STDOUT_FILENO);
3037 /* find out how many entries can be put on one line, with two spaces between strings */
3038 limit = screenwidth / (max + 2);
3042 /* how many lines of output */
3043 count = len / limit;
3044 if (count * limit < len)
3049 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
3051 for (; count > 0; count--) {
3053 for (i = 0; i < limit && matches[idx]; i++, idx++) {
3055 /* Don't print dupes */
3056 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
3058 ast_free(matches[idx]);
3059 matches[idx] = NULL;
3065 fprintf(stdout, "%-*s ", max, matches[idx]);
3066 ast_free(matches[idx]);
3067 matches[idx] = NULL;
3069 if (numoutputline > 0)
3070 fprintf(stdout, "\n");
3077 static char *cli_complete(EditLine *editline, int ch)
3083 int retval = CC_ERROR;
3084 char buf[2048], savechr;
3087 LineInfo *lf = (LineInfo *)el_line(editline);
3089 savechr = *(char *)lf->cursor;
3090 *(char *)lf->cursor = '\0';
3091 ptr = (char *)lf->cursor;
3093 while (ptr > lf->buffer) {
3094 if (isspace(*ptr)) {
3102 len = lf->cursor - ptr;
3104 if (ast_opt_remote) {
3105 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
3106 fdsend(ast_consock, buf);
3107 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
3108 return (char*)(CC_ERROR);
3111 nummatches = atoi(buf);
3113 if (nummatches > 0) {
3116 int mlen = 0, maxmbuf = 2048;
3118 /* Start with a 2048 byte buffer */
3119 if (!(mbuf = ast_malloc(maxmbuf))) {
3120 *((char *) lf->cursor) = savechr;
3121 return (char *)(CC_ERROR);
3123 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
3124 fdsend(ast_consock, buf);
3127 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
3128 if (mlen + 1024 > maxmbuf) {
3129 /* Every step increment buffer 1024 bytes */
3131 new_mbuf = ast_realloc(mbuf, maxmbuf);
3134 *((char *) lf->cursor) = savechr;
3135 return (char *)(CC_ERROR);
3139 /* Only read 1024 bytes at a time */
3140 res = read(ast_consock, mbuf + mlen, 1024);
3146 matches = ast_el_strtoarr(mbuf);
3149 matches = (char **) NULL;
3151 char **p, *oldbuf=NULL;
3153 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
3154 for (p = matches; p && *p; p++) {
3155 if (!oldbuf || strcmp(*p,oldbuf))
3163 int matches_num, maxlen, match_len;
3165 if (matches[0][0] != '\0') {
3166 el_deletestr(editline, (int) len);
3167 el_insertstr(editline, matches[0]);
3168 retval = CC_REFRESH;
3171 if (nummatches == 1) {
3172 /* Found an exact match */
3173 el_insertstr(editline, " ");
3174 retval = CC_REFRESH;
3176 /* Must be more than one match */
3177 for (i = 1, maxlen = 0; matches[i]; i++) {
3178 match_len = strlen(matches[i]);
3179 if (match_len > maxlen)
3182 matches_num = i - 1;
3183 if (matches_num >1) {
3184 fprintf(stdout, "\n");
3185 ast_cli_display_match_list(matches, nummatches, maxlen);
3186 retval = CC_REDISPLAY;
3188 el_insertstr(editline," ");
3189 retval = CC_REFRESH;
3192 for (i = 0; matches[i]; i++)
3193 ast_free(matches[i]);
3197 *((char *) lf->cursor) = savechr;
3199 return (char *)(long)retval;
3202 static int ast_el_initialize(void)
3205 char *editor, *editrc = getenv("EDITRC");
3207 if (!(editor = getenv("AST_EDITMODE"))) {
3208 if (!(editor = getenv("AST_EDITOR"))) {
3215 if (el_hist != NULL)
3216 history_end(el_hist);
3218 el = el_init("asterisk", stdin, stdout, stderr);
3219 el_set(el, EL_PROMPT, cli_prompt);
3221 el_set(el, EL_EDITMODE, 1);
3222 el_set(el, EL_EDITOR, editor);
3223 el_hist = history_init();
3224 if (!el || !el_hist)
3227 /* setup history with 100