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_REGISTER_FILE()
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 #include <sys/vmmeter.h>
175 #if defined(__FreeBSD__)
176 #include <vm/vm_param.h>
178 #if defined(HAVE_SWAPCTL)
179 #include <sys/swap.h>
183 #include <histedit.h>
186 int daemon(int, int); /* defined in libresolv of all places */
187 #include <sys/loadavg.h>
191 #include <sys/prctl.h>
193 #include <sys/capability.h>
194 #endif /* HAVE_CAP */
197 /* we define here the variables so to better agree on the prototype */
198 #include "asterisk/paths.h"
199 #include "asterisk/network.h"
200 #include "asterisk/cli.h"
201 #include "asterisk/channel.h"
202 #include "asterisk/translate.h"
203 #include "asterisk/pickup.h"
204 #include "asterisk/features.h"
205 #include "asterisk/acl.h"
206 #include "asterisk/ulaw.h"
207 #include "asterisk/alaw.h"
208 #include "asterisk/callerid.h"
209 #include "asterisk/image.h"
210 #include "asterisk/tdd.h"
211 #include "asterisk/term.h"
212 #include "asterisk/manager.h"
213 #include "asterisk/cdr.h"
214 #include "asterisk/cel.h"
215 #include "asterisk/pbx.h"
216 #include "asterisk/enum.h"
217 #include "asterisk/http.h"
218 #include "asterisk/udptl.h"
219 #include "asterisk/app.h"
220 #include "asterisk/lock.h"
221 #include "asterisk/utils.h"
222 #include "asterisk/file.h"
223 #include "asterisk/io.h"
224 #include "editline/histedit.h"
225 #include "asterisk/config.h"
226 #include "asterisk/ast_version.h"
227 #include "asterisk/linkedlists.h"
228 #include "asterisk/devicestate.h"
229 #include "asterisk/presencestate.h"
230 #include "asterisk/module.h"
231 #include "asterisk/dsp.h"
232 #include "asterisk/buildinfo.h"
233 #include "asterisk/xmldoc.h"
234 #include "asterisk/poll-compat.h"
235 #include "asterisk/ccss.h"
236 #include "asterisk/test.h"
237 #include "asterisk/rtp_engine.h"
238 #include "asterisk/format.h"
239 #include "asterisk/aoc.h"
240 #include "asterisk/uuid.h"
241 #include "asterisk/sorcery.h"
242 #include "asterisk/bucket.h"
243 #include "asterisk/stasis.h"
244 #include "asterisk/json.h"
245 #include "asterisk/stasis_endpoints.h"
246 #include "asterisk/stasis_system.h"
247 #include "asterisk/security_events.h"
248 #include "asterisk/endpoints.h"
249 #include "asterisk/codec.h"
250 #include "asterisk/format_cache.h"
252 #include "../defaults.h"
255 <managerEvent language="en_US" name="FullyBooted">
256 <managerEventInstance class="EVENT_FLAG_SYSTEM">
257 <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
259 <parameter name="Status">
260 <para>Informational message</para>
263 </managerEventInstance>
265 <managerEvent language="en_US" name="Shutdown">
266 <managerEventInstance class="EVENT_FLAG_SYSTEM">
267 <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
269 <parameter name="Shutdown">
270 <para>Whether the shutdown is proceeding cleanly (all channels
271 were hungup successfully) or uncleanly (channels will be
274 <enum name="Uncleanly"/>
275 <enum name="Cleanly"/>
278 <parameter name="Restart">
279 <para>Whether or not a restart will occur.</para>
286 </managerEventInstance>
291 #define AF_LOCAL AF_UNIX
292 #define PF_LOCAL PF_UNIX
295 #define AST_MAX_CONNECTS 128
298 /*! Default minimum DTMF digit length - 80ms */
299 #define AST_MIN_DTMF_DURATION 80
302 /*! \brief Welcome message when starting a CLI interface */
303 #define WELCOME_MESSAGE \
304 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2014, Digium, Inc. and others.\n" \
305 "Created by Mark Spencer <markster@digium.com>\n" \
306 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
307 "This is free software, with components licensed under the GNU General Public\n" \
308 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
309 "certain conditions. Type 'core show license' for details.\n" \
310 "=========================================================================\n", ast_get_version()) \
312 /*! \defgroup main_options Main Configuration Options
313 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
314 * \arg \ref Config_ast "asterisk.conf"
315 * \note Some of them can be changed in the CLI
319 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
321 /*! Maximum active system verbosity level. */
322 int ast_verb_sys_level;
324 int option_verbose; /*!< Verbosity level */
325 int option_debug; /*!< Debug level */
326 double ast_option_maxload; /*!< Max load avg on system */
327 int ast_option_maxcalls; /*!< Max number of active calls */
328 int ast_option_maxfiles; /*!< Max number of open file handles (files, sockets) */
329 unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */
330 #if defined(HAVE_SYSINFO)
331 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
336 struct ast_eid ast_eid_default;
338 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
339 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
341 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
342 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
345 int fd; /*!< File descriptor */
346 int p[2]; /*!< Pipe */
347 pthread_t t; /*!< Thread of handler */
348 int mute; /*!< Is the console muted for logs */
349 int uid; /*!< Remote user ID. */
350 int gid; /*!< Remote group ID. */
351 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
352 /*! Verbosity level of this console. */
359 AST_LIST_ENTRY(ast_atexit) list;
362 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
364 struct timeval ast_startuptime;
365 struct timeval ast_lastreloadtime;
367 static History *el_hist;
369 static char *remotehostname;
371 struct console consoles[AST_MAX_CONNECTS];
373 char ast_defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
375 static int ast_el_add_history(char *);
376 static int ast_el_read_history(char *);
377 static int ast_el_write_history(char *);
380 char config_dir[PATH_MAX];
381 char module_dir[PATH_MAX];
382 char spool_dir[PATH_MAX];
383 char monitor_dir[PATH_MAX];
384 char recording_dir[PATH_MAX];
385 char var_dir[PATH_MAX];
386 char data_dir[PATH_MAX];
387 char log_dir[PATH_MAX];
388 char agi_dir[PATH_MAX];
389 char run_dir[PATH_MAX];
390 char key_dir[PATH_MAX];
392 char config_file[PATH_MAX];
393 char db_path[PATH_MAX];
394 char sbin_dir[PATH_MAX];
395 char pid_path[PATH_MAX];
396 char socket_path[PATH_MAX];
397 char run_user[PATH_MAX];
398 char run_group[PATH_MAX];
399 char system_name[128];
402 static struct _cfg_paths cfg_paths;
404 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
405 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
406 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
407 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
408 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
409 const char *ast_config_AST_RECORDING_DIR = cfg_paths.recording_dir;
410 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
411 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
412 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
413 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
414 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
415 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
416 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
418 const char *ast_config_AST_DB = cfg_paths.db_path;
419 const char *ast_config_AST_PID = cfg_paths.pid_path;
420 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
421 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
422 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
423 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
425 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
426 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
427 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
428 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
430 extern unsigned int ast_FD_SETSIZE;
432 static char *_argv[256];
435 /*! Normal operation */
437 /*! Committed to shutting down. Final phase */
439 /*! Committed to shutting down. Initial phase */
442 * Valid values for quit_handler() niceness below.
443 * These shutdown/restart levels can be cancelled.
445 * Remote console exit right now
448 /*! core stop/restart now */
450 /*! core stop/restart gracefully */
452 /*! core stop/restart when convenient */
456 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
458 /*! Prevent new channel allocation for shutdown. */
459 static int shutdown_pending;
461 static int restartnow;
462 static pthread_t consolethread = AST_PTHREADT_NULL;
463 static pthread_t mon_sig_flags;
464 static int canary_pid = 0;
465 static char canary_filename[128];
466 static int multi_thread_safe;
468 static char randompool[256];
470 static int sig_alert_pipe[2] = { -1, -1 };
472 unsigned int need_reload:1;
473 unsigned int need_quit:1;
474 unsigned int need_quit_handler:1;
477 #if !defined(LOW_MEMORY)
478 struct registered_file {
479 AST_RWLIST_ENTRY(registered_file) list;
483 static AST_RWLIST_HEAD_STATIC(registered_files, registered_file);
485 void __ast_register_file(const char *file)
487 struct registered_file *reg;
489 reg = ast_calloc(1, sizeof(*reg));
495 AST_RWLIST_WRLOCK(®istered_files);
496 AST_RWLIST_INSERT_HEAD(®istered_files, reg, list);
497 AST_RWLIST_UNLOCK(®istered_files);
500 void __ast_unregister_file(const char *file)
502 struct registered_file *find;
504 AST_RWLIST_WRLOCK(®istered_files);
505 AST_RWLIST_TRAVERSE_SAFE_BEGIN(®istered_files, find, list) {
506 if (!strcasecmp(find->file, file)) {
507 AST_RWLIST_REMOVE_CURRENT(list);
511 AST_RWLIST_TRAVERSE_SAFE_END;
512 AST_RWLIST_UNLOCK(®istered_files);
519 char *ast_complete_source_filename(const char *partial, int n)
521 struct registered_file *find;
522 size_t len = strlen(partial);
526 AST_RWLIST_RDLOCK(®istered_files);
527 AST_RWLIST_TRAVERSE(®istered_files, find, list) {
528 if (!strncasecmp(find->file, partial, len) && ++count > n) {
529 res = ast_strdup(find->file);
533 AST_RWLIST_UNLOCK(®istered_files);
537 struct thread_list_t {
538 AST_RWLIST_ENTRY(thread_list_t) list;
544 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
546 void ast_register_thread(char *name)
548 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
553 ast_assert(multi_thread_safe);
554 new->id = pthread_self();
555 new->lwp = ast_get_tid();
556 new->name = name; /* steal the allocated memory for the thread name */
557 AST_RWLIST_WRLOCK(&thread_list);
558 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
559 AST_RWLIST_UNLOCK(&thread_list);
562 void ast_unregister_thread(void *id)
564 struct thread_list_t *x;
566 AST_RWLIST_WRLOCK(&thread_list);
567 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
568 if ((void *) x->id == id) {
569 AST_RWLIST_REMOVE_CURRENT(list);
573 AST_RWLIST_TRAVERSE_SAFE_END;
574 AST_RWLIST_UNLOCK(&thread_list);
581 /*! \brief Give an overview of core settings */
582 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
590 e->command = "core show settings";
591 e->usage = "Usage: core show settings\n"
592 " Show core misc settings";
598 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
600 ast_cli(a->fd, "\nPBX Core settings\n");
601 ast_cli(a->fd, "-----------------\n");
602 ast_cli(a->fd, " Version: %s\n", ast_get_version());
603 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
604 if (ast_option_maxcalls)
605 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", ast_option_maxcalls, ast_active_channels());
607 ast_cli(a->fd, " Maximum calls: Not set\n");
608 if (ast_option_maxfiles)
609 ast_cli(a->fd, " Maximum open file handles: %d\n", ast_option_maxfiles);
611 ast_cli(a->fd, " Maximum open file handles: Not set\n");
612 ast_cli(a->fd, " Root console verbosity: %d\n", option_verbose);
613 ast_cli(a->fd, " Current console verbosity: %d\n", ast_verb_console_get());
614 ast_cli(a->fd, " Debug level: %d\n", option_debug);
615 ast_cli(a->fd, " Maximum load average: %lf\n", ast_option_maxload);
616 #if defined(HAVE_SYSINFO)
617 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
619 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
620 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
621 ast_cli(a->fd, " Startup time: %s\n", buf);
623 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
624 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
625 ast_cli(a->fd, " Last reload time: %s\n", buf);
627 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);
628 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
629 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
630 ast_cli(a->fd, " Default language: %s\n", ast_defaultlanguage);
631 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
632 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
633 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
634 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
635 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
636 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
637 ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
639 ast_cli(a->fd, "\n* Subsystems\n");
640 ast_cli(a->fd, " -------------\n");
641 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
642 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
643 ast_cli(a->fd, " Call data records: %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
644 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
646 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
648 ast_cli(a->fd, "\n* Directories\n");
649 ast_cli(a->fd, " -------------\n");
650 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
651 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
652 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
653 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
654 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
655 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
656 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
657 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
658 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
659 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
660 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
661 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
662 ast_cli(a->fd, "\n\n");
666 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
669 struct thread_list_t *cur;
672 e->command = "core show threads";
674 "Usage: core show threads\n"
675 " List threads currently active in the system.\n";
681 AST_RWLIST_RDLOCK(&thread_list);
682 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
683 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
686 AST_RWLIST_UNLOCK(&thread_list);
687 ast_cli(a->fd, "%d threads listed.\n", count);
691 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
693 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
694 * to be based on the new swapctl(2) system call.
696 static int swapmode(int *used, int *total)
698 struct swapent *swdev;
699 int nswap, rnswap, i;
701 nswap = swapctl(SWAP_NSWAP, 0, 0);
705 swdev = ast_calloc(nswap, sizeof(*swdev));
709 rnswap = swapctl(SWAP_STATS, swdev, nswap);
715 /* if rnswap != nswap, then what? */
717 /* Total things up */
719 for (i = 0; i < nswap; i++) {
720 if (swdev[i].se_flags & SWF_ENABLE) {
721 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
722 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
728 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
729 static int swapmode(int *used, int *total)
736 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
737 /*! \brief Give an overview of system statistics */
738 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
740 uint64_t physmem, freeram;
741 uint64_t freeswap = 0;
745 #if defined(HAVE_SYSINFO)
746 struct sysinfo sys_info;
748 uptime = sys_info.uptime / 3600;
749 physmem = sys_info.totalram * sys_info.mem_unit;
750 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
751 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
752 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
753 nprocs = sys_info.procs;
754 #elif defined(HAVE_SYSCTL)
755 static int pageshift;
756 struct vmtotal vmtotal;
757 struct timeval boottime;
759 int mib[2], pagesize, usedswap = 0;
761 /* calculate the uptime by looking at boottime */
764 mib[1] = KERN_BOOTTIME;
765 len = sizeof(boottime);
766 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
767 uptime = now - boottime.tv_sec;
769 uptime = uptime/3600;
770 /* grab total physical memory */
772 #if defined(HW_PHYSMEM64)
773 mib[1] = HW_PHYSMEM64;
777 len = sizeof(physmem);
778 sysctl(mib, 2, &physmem, &len, NULL, 0);
780 pagesize = getpagesize();
782 while (pagesize > 1) {
787 /* we only need the amount of log(2)1024 for our conversion */
793 len = sizeof(vmtotal);
794 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
795 freeram = (vmtotal.t_free << pageshift);
796 /* generate swap usage and totals */
797 swapmode(&usedswap, &totalswap);
798 freeswap = (totalswap - usedswap);
799 /* grab number of processes */
800 #if defined(__OpenBSD__)
802 mib[1] = KERN_NPROCS;
803 len = sizeof(nprocs);
804 sysctl(mib, 2, &nprocs, &len, NULL, 0);
810 e->command = "core show sysinfo";
812 "Usage: core show sysinfo\n"
813 " List current system information.\n";
819 ast_cli(a->fd, "\nSystem Statistics\n");
820 ast_cli(a->fd, "-----------------\n");
821 ast_cli(a->fd, " System Uptime: %ld hours\n", uptime);
822 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
823 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
824 #if defined(HAVE_SYSINFO)
825 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
827 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
828 ast_cli(a->fd, " Total Swap Space: %d KiB\n", totalswap);
829 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
831 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
836 struct profile_entry {
838 uint64_t scale; /* if non-zero, values are scaled by this */
844 struct profile_data {
847 struct profile_entry e[0];
850 static struct profile_data *prof_data;
852 /*! \brief allocates a counter with a given name and scale.
853 * \return Returns the identifier of the counter.
855 int ast_add_profile(const char *name, uint64_t scale)
857 int l = sizeof(struct profile_data);
858 int n = 10; /* default entries */
860 if (prof_data == NULL) {
861 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
862 if (prof_data == NULL)
864 prof_data->entries = 0;
865 prof_data->max_size = n;
867 if (prof_data->entries >= prof_data->max_size) {
869 n = prof_data->max_size + 20;
870 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
874 prof_data->max_size = n;
876 n = prof_data->entries++;
877 prof_data->e[n].name = ast_strdup(name);
878 prof_data->e[n].value = 0;
879 prof_data->e[n].events = 0;
880 prof_data->e[n].mark = 0;
881 prof_data->e[n].scale = scale;
885 int64_t ast_profile(int i, int64_t delta)
887 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
889 if (prof_data->e[i].scale > 1)
890 delta /= prof_data->e[i].scale;
891 prof_data->e[i].value += delta;
892 prof_data->e[i].events++;
893 return prof_data->e[i].value;
896 /* The RDTSC instruction was introduced on the Pentium processor and is not
897 * implemented on certain clones, like the Cyrix 586. Hence, the previous
898 * expectation of __i386__ was in error. */
899 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
900 #if defined(__FreeBSD__)
901 #include <machine/cpufunc.h>
903 static __inline uint64_t
908 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
912 #else /* supply a dummy function on other platforms */
913 static __inline uint64_t
920 int64_t ast_mark(int i, int startstop)
922 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
925 prof_data->e[i].mark = rdtsc();
927 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
928 if (prof_data->e[i].scale > 1)
929 prof_data->e[i].mark /= prof_data->e[i].scale;
930 prof_data->e[i].value += prof_data->e[i].mark;
931 prof_data->e[i].events++;
933 return prof_data->e[i].mark;
936 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
937 max = prof_data->entries;\
938 if (a->argc > 3) { /* specific entries */ \
939 if (isdigit(a->argv[3][0])) { \
940 min = atoi(a->argv[3]); \
941 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
942 max = atoi(a->argv[4]); \
944 search = a->argv[3]; \
946 if (max > prof_data->entries) \
947 max = prof_data->entries;
949 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
952 const char *search = NULL;
955 e->command = "core show profile";
956 e->usage = "Usage: core show profile\n"
957 " show profile information";
963 if (prof_data == NULL)
966 DEFINE_PROFILE_MIN_MAX_VALUES;
967 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
968 prof_data->entries, prof_data->max_size);
969 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
970 "Value", "Average", "Name");
971 for (i = min; i < max; i++) {
972 struct profile_entry *entry = &prof_data->e[i];
973 if (!search || strstr(entry->name, search))
974 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
977 (long)entry->events, (long long)entry->value,
978 (long long)(entry->events ? entry->value / entry->events : entry->value),
984 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
987 const char *search = NULL;
990 e->command = "core clear profile";
991 e->usage = "Usage: core clear profile\n"
992 " clear profile information";
998 if (prof_data == NULL)
1001 DEFINE_PROFILE_MIN_MAX_VALUES;
1002 for (i= min; i < max; i++) {
1003 if (!search || strstr(prof_data->e[i].name, search)) {
1004 prof_data->e[i].value = 0;
1005 prof_data->e[i].events = 0;
1010 #undef DEFINE_PROFILE_MIN_MAX_VALUES
1012 #endif /* ! LOW_MEMORY */
1014 static void publish_fully_booted(void)
1016 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1018 json_object = ast_json_pack("{s: s}",
1019 "Status", "Fully Booted");
1020 ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
1023 static void ast_run_atexits(int run_cleanups)
1025 struct ast_atexit *ae;
1027 AST_LIST_LOCK(&atexits);
1028 while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1029 if (ae->func && (!ae->is_cleanup || run_cleanups)) {
1034 AST_LIST_UNLOCK(&atexits);
1037 static void __ast_unregister_atexit(void (*func)(void))
1039 struct ast_atexit *ae;
1041 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1042 if (ae->func == func) {
1043 AST_LIST_REMOVE_CURRENT(list);
1048 AST_LIST_TRAVERSE_SAFE_END;
1051 static int register_atexit(void (*func)(void), int is_cleanup)
1053 struct ast_atexit *ae;
1055 ae = ast_calloc(1, sizeof(*ae));
1060 ae->is_cleanup = is_cleanup;
1062 AST_LIST_LOCK(&atexits);
1063 __ast_unregister_atexit(func);
1064 AST_LIST_INSERT_HEAD(&atexits, ae, list);
1065 AST_LIST_UNLOCK(&atexits);
1070 int ast_register_atexit(void (*func)(void))
1072 return register_atexit(func, 0);
1075 int ast_register_cleanup(void (*func)(void))
1077 return register_atexit(func, 1);
1080 void ast_unregister_atexit(void (*func)(void))
1082 AST_LIST_LOCK(&atexits);
1083 __ast_unregister_atexit(func);
1084 AST_LIST_UNLOCK(&atexits);
1087 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1088 static int fdsend(int fd, const char *s)
1090 return write(fd, s, strlen(s) + 1);
1093 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1094 static int fdprint(int fd, const char *s)
1096 return write(fd, s, strlen(s));
1099 /*! \brief NULL handler so we can collect the child exit status */
1100 static void _null_sig_handler(int sig)
1104 static struct sigaction null_sig_handler = {
1105 .sa_handler = _null_sig_handler,
1106 .sa_flags = SA_RESTART,
1109 static struct sigaction ignore_sig_handler = {
1110 .sa_handler = SIG_IGN,
1113 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1114 /*! \brief Keep track of how many threads are currently trying to wait*() on
1117 static unsigned int safe_system_level = 0;
1118 static struct sigaction safe_system_prev_handler;
1120 void ast_replace_sigchld(void)
1124 ast_mutex_lock(&safe_system_lock);
1125 level = safe_system_level++;
1127 /* only replace the handler if it has not already been done */
1129 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1132 ast_mutex_unlock(&safe_system_lock);
1135 void ast_unreplace_sigchld(void)
1139 ast_mutex_lock(&safe_system_lock);
1140 level = --safe_system_level;
1142 /* only restore the handler if we are the last one */
1144 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1147 ast_mutex_unlock(&safe_system_lock);
1150 int ast_safe_system(const char *s)
1156 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1157 ast_replace_sigchld();
1159 #ifdef HAVE_WORKING_FORK
1167 cap_t cap = cap_from_text("cap_net_admin-eip");
1169 if (cap_set_proc(cap)) {
1170 /* Careful with order! Logging cannot happen after we close FDs */
1171 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1175 #ifdef HAVE_WORKING_FORK
1176 if (ast_opt_high_priority)
1177 ast_set_priority(0);
1178 /* Close file descriptors and launch system command */
1179 ast_close_fds_above_n(STDERR_FILENO);
1181 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1183 } else if (pid > 0) {
1185 res = waitpid(pid, &status, 0);
1187 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1189 } else if (errno != EINTR)
1193 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1197 ast_unreplace_sigchld();
1198 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1206 * \brief enable or disable a logging level to a specified console
1208 void ast_console_toggle_loglevel(int fd, int level, int state)
1212 if (level >= NUMLOGLEVELS) {
1213 level = NUMLOGLEVELS - 1;
1216 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1217 if (fd == consoles[x].fd) {
1219 * Since the logging occurs when levels are false, set to
1220 * flipped iinput because this function accepts 0 as off and 1 as on
1222 consoles[x].levels[level] = state ? 0 : 1;
1229 * \brief mute or unmute a console from logging
1231 void ast_console_toggle_mute(int fd, int silent)
1234 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1235 if (fd == consoles[x].fd) {
1236 if (consoles[x].mute) {
1237 consoles[x].mute = 0;
1239 ast_cli(fd, "Console is not muted anymore.\n");
1241 consoles[x].mute = 1;
1243 ast_cli(fd, "Console is muted.\n");
1248 ast_cli(fd, "Couldn't find remote console.\n");
1252 * \brief log the string to all attached network console clients
1254 static void ast_network_puts_mutable(const char *string, int level)
1258 for (x = 0; x < AST_MAX_CONNECTS; ++x) {
1259 if (consoles[x].fd < 0
1261 || consoles[x].levels[level]) {
1264 fdprint(consoles[x].p[1], string);
1269 * \brief log the string to the root console, and all attached
1270 * network console clients
1272 void ast_console_puts_mutable(const char *string, int level)
1274 /* Send to the root console */
1275 fputs(string, stdout);
1278 /* Send to any network console clients */
1279 ast_network_puts_mutable(string, level);
1283 * \brief write the string to all attached console clients
1285 static void ast_network_puts(const char *string)
1289 for (x = 0; x < AST_MAX_CONNECTS; ++x) {
1290 if (consoles[x].fd < 0) {
1293 fdprint(consoles[x].p[1], string);
1298 * \brief write the string to the root console, and all attached
1299 * network console clients
1301 void ast_console_puts(const char *string)
1303 /* Send to the root console */
1304 fputs(string, stdout);
1307 /* Send to any network console clients */
1308 ast_network_puts(string);
1311 static void network_verboser(const char *string)
1316 /* Send to any network console clients if client verbocity allows. */
1317 verb_level = VERBOSE_MAGIC2LEVEL(string);
1318 for (x = 0; x < AST_MAX_CONNECTS; ++x) {
1319 if (consoles[x].fd < 0
1321 || consoles[x].levels[__LOG_VERBOSE]
1322 || consoles[x].option_verbose < verb_level) {
1325 fdprint(consoles[x].p[1], string);
1329 static pthread_t lthread;
1332 * \brief read() function supporting the reception of user credentials.
1334 * \param fd Socket file descriptor.
1335 * \param buffer Receive buffer.
1336 * \param size 'buffer' size.
1337 * \param con Console structure to set received credentials
1338 * \retval -1 on error
1339 * \retval the number of bytes received on success.
1341 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1343 #if defined(SO_PEERCRED)
1344 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1345 #define HAVE_STRUCT_UCRED_UID
1346 struct sockpeercred cred;
1350 socklen_t len = sizeof(cred);
1352 #if defined(HAVE_GETPEEREID)
1360 result = read(fd, buffer, size);
1365 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1366 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1369 #if defined(HAVE_STRUCT_UCRED_UID)
1372 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1375 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1377 #elif defined(HAVE_GETPEEREID)
1378 if (getpeereid(fd, &uid, &gid)) {
1390 /* This is the thread running the remote console on the main process. */
1391 static void *netconsole(void *vconsole)
1393 struct console *con = vconsole;
1394 char hostname[MAXHOSTNAMELEN] = "";
1397 const char * const end_buf = inbuf + sizeof(inbuf);
1398 char *start_read = inbuf;
1400 struct pollfd fds[2];
1402 if (gethostname(hostname, sizeof(hostname)-1))
1403 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1404 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1405 fdprint(con->fd, outbuf);
1406 ast_verb_console_register(&con->option_verbose);
1408 fds[0].fd = con->fd;
1409 fds[0].events = POLLIN;
1411 fds[1].fd = con->p[0];
1412 fds[1].events = POLLIN;
1415 res = ast_poll(fds, 2, -1);
1418 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1421 if (fds[0].revents) {
1422 int cmds_read, bytes_read;
1423 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1426 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1427 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1428 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1431 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1432 * NULL and not trailing partial commands. */
1433 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1434 /* No commands were read. We either have a short read on the first command
1435 * with space left, or a command that is too long */
1436 if (start_read + bytes_read < end_buf) {
1437 start_read += bytes_read;
1439 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1444 if (start_read[bytes_read - 1] == '\0') {
1445 /* The read ended on a command boundary, start reading again at the head of inbuf */
1449 /* If we get this far, we have left over characters that have not been processed.
1450 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1451 * We are guaranteed to have at least cmds_read NULLs */
1452 while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1455 memmove(inbuf, start_read, end_buf - start_read);
1456 start_read = end_buf - start_read + inbuf;
1458 if (fds[1].revents) {
1459 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1461 ast_log(LOG_ERROR, "read returned %d\n", res);
1464 res = write(con->fd, outbuf, res);
1469 ast_verb_console_unregister();
1470 if (!ast_opt_hide_connect) {
1471 ast_verb(3, "Remote UNIX connection disconnected\n");
1481 static void *listener(void *unused)
1483 struct sockaddr_un sunaddr;
1488 struct pollfd fds[1];
1492 fds[0].fd = ast_socket;
1493 fds[0].events = POLLIN;
1494 s = ast_poll(fds, 1, -1);
1495 pthread_testcancel();
1498 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1501 len = sizeof(sunaddr);
1502 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1505 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1507 #if defined(SO_PASSCRED)
1509 /* turn on socket credentials passing. */
1510 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1511 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1515 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1516 if (consoles[x].fd >= 0) {
1519 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1520 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1521 fdprint(s, "Server failed to create pipe\n");
1525 flags = fcntl(consoles[x].p[1], F_GETFL);
1526 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1527 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1528 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1529 to know if the user didn't send the credentials. */
1530 consoles[x].uid = -2;
1531 consoles[x].gid = -2;
1532 /* Server default of remote console verbosity level is OFF. */
1533 consoles[x].option_verbose = 0;
1535 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1536 consoles[x].fd = -1;
1537 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1538 close(consoles[x].p[0]);
1539 close(consoles[x].p[1]);
1540 fdprint(s, "Server failed to spawn thread\n");
1545 if (x >= AST_MAX_CONNECTS) {
1546 fdprint(s, "No more connections allowed\n");
1547 ast_log(LOG_WARNING, "No more connections allowed\n");
1549 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1550 ast_verb(3, "Remote UNIX connection\n");
1558 static int ast_makesocket(void)
1560 struct sockaddr_un sunaddr;
1566 for (x = 0; x < AST_MAX_CONNECTS; x++)
1567 consoles[x].fd = -1;
1568 unlink(ast_config_AST_SOCKET);
1569 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1570 if (ast_socket < 0) {
1571 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1574 memset(&sunaddr, 0, sizeof(sunaddr));
1575 sunaddr.sun_family = AF_LOCAL;
1576 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1577 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1579 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1584 res = listen(ast_socket, 2);
1586 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1591 if (ast_register_verbose(network_verboser)) {
1592 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1595 if (ast_pthread_create_background(<hread, NULL, listener, NULL)) {
1596 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1601 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1603 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1604 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1609 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1611 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1612 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1617 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1618 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1620 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1623 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1625 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1626 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1632 static int ast_tryconnect(void)
1634 struct sockaddr_un sunaddr;
1636 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1637 if (ast_consock < 0) {
1638 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1641 memset(&sunaddr, 0, sizeof(sunaddr));
1642 sunaddr.sun_family = AF_LOCAL;
1643 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1644 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1653 /*! \brief Urgent handler
1655 * Called by soft_hangup to interrupt the poll, read, or other
1656 * system call. We don't actually need to do anything though.
1657 * Remember: Cannot EVER ast_log from within a signal handler
1659 static void _urg_handler(int num)
1664 static struct sigaction urg_handler = {
1665 .sa_handler = _urg_handler,
1666 .sa_flags = SA_RESTART,
1669 static void _hup_handler(int num)
1671 int a = 0, save_errno = errno;
1672 printf("Received HUP signal -- Reloading configs\n");
1674 execvp(_argv[0], _argv);
1675 sig_flags.need_reload = 1;
1676 if (sig_alert_pipe[1] != -1) {
1677 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1678 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1684 static struct sigaction hup_handler = {
1685 .sa_handler = _hup_handler,
1686 .sa_flags = SA_RESTART,
1689 static void _child_handler(int sig)
1691 /* Must not ever ast_log or ast_verbose within signal handler */
1692 int n, status, save_errno = errno;
1695 * Reap all dead children -- not just one
1697 for (n = 0; waitpid(-1, &status, WNOHANG) > 0; n++)
1699 if (n == 0 && option_debug)
1700 printf("Huh? Child handler, but nobody there?\n");
1704 static struct sigaction child_handler = {
1705 .sa_handler = _child_handler,
1706 .sa_flags = SA_RESTART,
1709 /*! \brief Set maximum open files */
1710 static void set_ulimit(int value)
1712 struct rlimit l = {0, 0};
1715 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1722 if (setrlimit(RLIMIT_NOFILE, &l)) {
1723 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1727 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1732 /*! \brief Set an X-term or screen title */
1733 static void set_title(char *text)
1735 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1736 fprintf(stdout, "\033]2;%s\007", text);
1739 static void set_icon(char *text)
1741 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1742 fprintf(stdout, "\033]1;%s\007", text);
1745 /*! \brief We set ourselves to a high priority, that we might pre-empt
1746 * everything else. If your PBX has heavy activity on it, this is a
1749 int ast_set_priority(int pri)
1751 struct sched_param sched;
1752 memset(&sched, 0, sizeof(sched));
1755 sched.sched_priority = 10;
1756 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1757 ast_log(LOG_WARNING, "Unable to set high priority\n");
1760 ast_verb(1, "Set to realtime thread\n");
1762 sched.sched_priority = 0;
1763 /* According to the manpage, these parameters can never fail. */
1764 sched_setscheduler(0, SCHED_OTHER, &sched);
1768 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1769 ast_log(LOG_WARNING, "Unable to set high priority\n");
1772 ast_verb(1, "Set to high priority\n");
1774 /* According to the manpage, these parameters can never fail. */
1775 setpriority(PRIO_PROCESS, 0, 0);
1781 int ast_shutdown_final(void)
1783 return shuttingdown == SHUTTING_DOWN_FINAL;
1786 int ast_shutting_down(void)
1788 return shutdown_pending;
1791 int ast_cancel_shutdown(void)
1793 int shutdown_aborted = 0;
1795 ast_mutex_lock(&safe_system_lock);
1796 if (shuttingdown >= SHUTDOWN_FAST) {
1797 shuttingdown = NOT_SHUTTING_DOWN;
1798 shutdown_pending = 0;
1799 shutdown_aborted = 1;
1801 ast_mutex_unlock(&safe_system_lock);
1802 return shutdown_aborted;
1807 * \brief Initiate system shutdown -- prevents new channels from being allocated.
1809 static void ast_begin_shutdown(void)
1811 ast_mutex_lock(&safe_system_lock);
1812 if (shuttingdown != NOT_SHUTTING_DOWN) {
1813 shutdown_pending = 1;
1815 ast_mutex_unlock(&safe_system_lock);
1818 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1819 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1821 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1823 if (can_safely_quit(niceness, restart)) {
1824 really_quit(num, niceness, restart);
1825 /* No one gets here. */
1827 /* It wasn't our time. */
1830 #define SHUTDOWN_TIMEOUT 15 /* Seconds */
1834 * \brief Wait for all channels to die, a timeout, or shutdown cancelled.
1837 * \param niceness Shutdown niceness in effect
1838 * \param seconds Number of seconds to wait or less than zero if indefinitely.
1840 * \retval zero if waiting wasn't necessary. We were idle.
1841 * \retval non-zero if we had to wait.
1843 static int wait_for_channels_to_die(shutdown_nice_t niceness, int seconds)
1851 if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1855 /* No timeout so just poll every second */
1860 /* Wait up to the given seconds for all channels to go away */
1861 if (seconds < (now - start)) {
1865 /* Sleep 1/10 of a second */
1873 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1877 /* Check if someone else isn't already doing this. */
1878 ast_mutex_lock(&safe_system_lock);
1879 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1880 /* Already in progress and other request was less nice. */
1881 ast_mutex_unlock(&safe_system_lock);
1882 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1885 shuttingdown = niceness;
1886 ast_mutex_unlock(&safe_system_lock);
1888 /* Try to get as many CDRs as possible submitted to the backend engines
1889 * (if in batch mode). really_quit happens to call it again when running
1890 * the atexit handlers, otherwise this would be a bit early. */
1891 ast_cdr_engine_term();
1894 * Shutdown the message queue for the technology agnostic message channel.
1895 * This has to occur before we pause shutdown pending ast_undestroyed_channels.
1897 * XXX This is not reversed on shutdown cancel.
1901 if (niceness == SHUTDOWN_NORMAL) {
1902 /* Begin shutdown routine, hanging up active channels */
1903 ast_begin_shutdown();
1904 if (ast_opt_console) {
1905 ast_verb(0, "Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1907 ast_softhangup_all();
1908 waited |= wait_for_channels_to_die(niceness, SHUTDOWN_TIMEOUT);
1909 } else if (niceness >= SHUTDOWN_NICE) {
1910 if (niceness != SHUTDOWN_REALLY_NICE) {
1911 ast_begin_shutdown();
1913 if (ast_opt_console) {
1914 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1916 waited |= wait_for_channels_to_die(niceness, -1);
1919 /* Re-acquire lock and check if someone changed the niceness, in which
1920 * case someone else has taken over the shutdown.
1922 ast_mutex_lock(&safe_system_lock);
1923 if (shuttingdown != niceness) {
1924 if (shuttingdown == NOT_SHUTTING_DOWN && ast_opt_console) {
1925 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1927 ast_mutex_unlock(&safe_system_lock);
1931 if (niceness >= SHUTDOWN_REALLY_NICE) {
1932 shuttingdown = SHUTTING_DOWN;
1933 ast_mutex_unlock(&safe_system_lock);
1935 /* No more Mr. Nice guy. We are committed to shutting down now. */
1936 ast_begin_shutdown();
1937 ast_softhangup_all();
1938 waited |= wait_for_channels_to_die(SHUTTING_DOWN, SHUTDOWN_TIMEOUT);
1940 ast_mutex_lock(&safe_system_lock);
1942 shuttingdown = SHUTTING_DOWN_FINAL;
1943 ast_mutex_unlock(&safe_system_lock);
1945 if (niceness >= SHUTDOWN_NORMAL && waited) {
1947 * We were not idle. Give things in progress a chance to
1948 * recognize the final shutdown phase.
1955 /*! Called when exiting is certain. */
1956 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1958 int active_channels;
1959 struct ast_json *json_object = NULL;
1960 int run_cleanups = niceness >= SHUTDOWN_NICE;
1963 ast_module_shutdown();
1966 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1967 char filename[80] = "";
1968 if (getenv("HOME")) {
1969 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1971 if (!ast_strlen_zero(filename)) {
1972 ast_el_write_history(filename);
1974 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1975 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1979 if (el_hist != NULL) {
1980 history_end(el_hist);
1982 } else if (mon_sig_flags == pthread_self()) {
1983 if (consolethread != AST_PTHREADT_NULL) {
1984 pthread_kill(consolethread, SIGURG);
1988 active_channels = ast_active_channels();
1989 /* Don't publish messages if we're a remote console - we won't have all of the Stasis
1990 * topics or message types
1992 if (!ast_opt_remote) {
1993 json_object = ast_json_pack("{s: s, s: s}",
1994 "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
1995 "Restart", restart ? "True" : "False");
1996 ast_manager_publish_event("Shutdown", EVENT_FLAG_SYSTEM, json_object);
1997 ast_json_unref(json_object);
2000 ast_verb(0, "Asterisk %s ending (%d).\n",
2001 active_channels ? "uncleanly" : "cleanly", num);
2003 ast_verb(0, "Executing last minute cleanups\n");
2004 ast_run_atexits(run_cleanups);
2006 ast_debug(1, "Asterisk ending (%d).\n", num);
2007 if (ast_socket > -1) {
2008 pthread_cancel(lthread);
2011 unlink(ast_config_AST_SOCKET);
2012 pthread_kill(lthread, SIGURG);
2013 pthread_join(lthread, NULL);
2015 if (ast_consock > -1)
2017 if (!ast_opt_remote)
2018 unlink(ast_config_AST_PID);
2019 if (sig_alert_pipe[0])
2020 close(sig_alert_pipe[0]);
2021 if (sig_alert_pipe[1])
2022 close(sig_alert_pipe[1]);
2023 printf("%s", term_quit());
2026 ast_verb(0, "Preparing for Asterisk restart...\n");
2027 /* Mark all FD's for closing on exec */
2028 for (i = 3; i < 32768; i++) {
2029 fcntl(i, F_SETFD, FD_CLOEXEC);
2031 ast_verb(0, "Asterisk is now restarting...\n");
2038 /* If there is a consolethread running send it a SIGHUP
2039 so it can execvp, otherwise we can do it ourselves */
2040 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
2041 pthread_kill(consolethread, SIGHUP);
2042 /* Give the signal handler some time to complete */
2045 execvp(_argv[0], _argv);
2056 static void __quit_handler(int num)
2059 sig_flags.need_quit = 1;
2060 if (sig_alert_pipe[1] != -1) {
2061 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
2062 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
2065 /* There is no need to restore the signal handler here, since the app
2066 * is going to exit */
2069 static void __remote_quit_handler(int num)
2071 sig_flags.need_quit = 1;
2074 static void set_header(char *outbuf, int maxout, char level)
2082 case 1: cmp = VERBOSE_PREFIX_1;
2084 case 2: cmp = VERBOSE_PREFIX_2;
2086 case 3: cmp = VERBOSE_PREFIX_3;
2088 default: cmp = VERBOSE_PREFIX_4;
2092 if (ast_opt_timestamp) {
2094 struct timeval now = ast_tvnow();
2095 ast_localtime(&now, &tm, NULL);
2096 ast_strftime(date, sizeof(date), ast_logger_get_dateformat(), &tm);
2099 snprintf(outbuf, maxout, "%s%s%s%s%s%s",
2100 ast_opt_timestamp ? "[" : "",
2101 ast_opt_timestamp ? date : "",
2102 ast_opt_timestamp ? "] " : "",
2103 cmp ? ast_term_color(COLOR_GRAY, 0) : "",
2105 cmp ? ast_term_reset() : "");
2108 struct console_state_data {
2109 char verbose_line_level;
2112 static int console_state_init(void *ptr)
2114 struct console_state_data *state = ptr;
2115 state->verbose_line_level = 0;
2119 AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr);
2121 static int console_print(const char *s, int local)
2123 struct console_state_data *state =
2124 ast_threadstorage_get(&console_state, sizeof(*state));
2129 unsigned int newline;
2132 if (VERBOSE_HASMAGIC(s)) {
2134 /* always use the given line's level, otherwise
2135 we'll use the last line's level */
2136 state->verbose_line_level = VERBOSE_MAGIC2LEVEL(s);
2138 /* move past magic */
2141 set_header(prefix, sizeof(prefix), state->verbose_line_level);
2147 /* for a given line separate on verbose magic, newline, and eol */
2148 if ((s = strchr(c, '\n'))) {
2152 s = strchr(c, '\0');
2156 /* check if we should write this line after calculating begin/end
2157 so we process the case of a higher level line embedded within
2158 two lower level lines */
2159 if (state->verbose_line_level > option_verbose) {
2163 if (!ast_strlen_zero(prefix)) {
2164 fputs(prefix, stdout);
2168 if (fwrite(c, sizeof(char), num, stdout) < num) {
2173 /* if at least some info has been written
2174 we'll want to return true */
2180 /* if ending on a newline then reset last level to zero
2181 since what follows may be not be logging output */
2182 state->verbose_line_level = 0;
2192 static void console_verboser(const char *s)
2194 if (!console_print(s, 1)) {
2198 /* Wake up a poll()ing console */
2199 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2200 pthread_kill(consolethread, SIGURG);
2204 static int ast_all_zeros(char *s)
2214 /* This is the main console CLI command handler. Run by the main() thread. */
2215 static void consolehandler(char *s)
2217 printf("%s", term_end());
2220 /* Called when readline data is available */
2221 if (!ast_all_zeros(s))
2222 ast_el_add_history(s);
2223 /* The real handler for bang */
2226 ast_safe_system(s+1);
2228 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2230 ast_cli_command(STDOUT_FILENO, s);
2233 static int remoteconsolehandler(char *s)
2237 /* Called when readline data is available */
2238 if (!ast_all_zeros(s))
2239 ast_el_add_history(s);
2241 while (isspace(*s)) {
2245 /* The real handler for bang */
2248 ast_safe_system(s+1);
2250 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2252 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2253 (s[4] == '\0' || isspace(s[4]))) {
2254 quit_handler(0, SHUTDOWN_FAST, 0);
2257 char *shrunk = ast_strdupa(s);
2262 * Remove duplicate spaces from shrunk for matching purposes.
2264 * shrunk has at least one character in it to start with or we
2265 * couldn't get here.
2267 for (prev = shrunk, cur = shrunk + 1; *cur; ++cur) {
2268 if (*prev == ' ' && *cur == ' ') {
2269 /* Skip repeated space delimiter. */
2276 if (strncasecmp(shrunk, "core set verbose ", 17) == 0) {
2278 * We need to still set the rasterisk option_verbose in case we are
2279 * talking to an earlier version which doesn't prefilter verbose
2280 * levels. This is really a compromise as we should always take
2281 * whatever the server sends.
2284 if (!strncasecmp(shrunk + 17, "off", 3)) {
2285 ast_verb_console_set(0);
2291 if (strncasecmp(shrunk + 17, "atleast ", atleast)) {
2295 if (sscanf(shrunk + 17 + atleast, "%30d", &verbose_new) == 1) {
2296 if (!atleast || ast_verb_console_get() < verbose_new) {
2297 ast_verb_console_set(verbose_new);
2307 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2311 e->command = "core show version";
2313 "Usage: core show version\n"
2314 " Shows Asterisk version information.\n";
2321 return CLI_SHOWUSAGE;
2322 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2323 ast_get_version(), ast_build_user, ast_build_hostname,
2324 ast_build_machine, ast_build_os, ast_build_date);
2329 static int handle_quit(int fd, int argc, char *argv[])
2332 return RESULT_SHOWUSAGE;
2333 quit_handler(0, SHUTDOWN_NORMAL, 0);
2334 return RESULT_SUCCESS;
2338 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2342 e->command = "core stop now";
2344 "Usage: core stop now\n"
2345 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2351 if (a->argc != e->args)
2352 return CLI_SHOWUSAGE;
2353 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2357 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2361 e->command = "core stop gracefully";
2363 "Usage: core stop gracefully\n"
2364 " Causes Asterisk to not accept new calls, and exit when all\n"
2365 " active calls have terminated normally.\n";
2371 if (a->argc != e->args)
2372 return CLI_SHOWUSAGE;
2373 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2377 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2381 e->command = "core stop when convenient";
2383 "Usage: core stop when convenient\n"
2384 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2390 if (a->argc != e->args)
2391 return CLI_SHOWUSAGE;
2392 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2393 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2397 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2401 e->command = "core restart now";
2403 "Usage: core restart now\n"
2404 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2411 if (a->argc != e->args)
2412 return CLI_SHOWUSAGE;
2413 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2417 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2421 e->command = "core restart gracefully";
2423 "Usage: core restart gracefully\n"
2424 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2425 " restart when all active calls have ended.\n";
2431 if (a->argc != e->args)
2432 return CLI_SHOWUSAGE;
2433 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2437 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2441 e->command = "core restart when convenient";
2443 "Usage: core restart when convenient\n"
2444 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2450 if (a->argc != e->args)
2451 return CLI_SHOWUSAGE;
2452 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2453 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2457 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2461 e->command = "core abort shutdown";
2463 "Usage: core abort shutdown\n"
2464 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2465 " call operations.\n";
2471 if (a->argc != e->args)
2472 return CLI_SHOWUSAGE;
2474 ast_cancel_shutdown();
2479 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2485 "Usage: !<command>\n"
2486 " Executes a given shell command\n";
2494 static const char warranty_lines[] = {
2498 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2499 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2500 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2501 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2502 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2503 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2504 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2505 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2506 "REPAIR OR CORRECTION.\n"
2508 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2509 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2510 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2511 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2512 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2513 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2514 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2515 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2516 "POSSIBILITY OF SUCH DAMAGES.\n"
2519 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2523 e->command = "core show warranty";
2525 "Usage: core show warranty\n"
2526 " Shows the warranty (if any) for this copy of Asterisk.\n";
2532 ast_cli(a->fd, "%s", warranty_lines);
2537 static const char license_lines[] = {
2539 "This program is free software; you can redistribute it and/or modify\n"
2540 "it under the terms of the GNU General Public License version 2 as\n"
2541 "published by the Free Software Foundation.\n"
2543 "This program also contains components licensed under other licenses.\n"
2546 "This program is distributed in the hope that it will be useful,\n"
2547 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2548 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2549 "GNU General Public License for more details.\n"
2551 "You should have received a copy of the GNU General Public License\n"
2552 "along with this program; if not, write to the Free Software\n"
2553 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2556 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2560 e->command = "core show license";
2562 "Usage: core show license\n"
2563 " Shows the license(s) for this copy of Asterisk.\n";
2569 ast_cli(a->fd, "%s", license_lines);
2574 #define ASTERISK_PROMPT "*CLI> "
2577 * \brief Shutdown Asterisk CLI commands.
2579 * \note These CLI commands cannot be unregistered at shutdown
2580 * because one of them is likely the reason for the shutdown.
2581 * The CLI generates a warning if a command is in-use when it is
2584 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2585 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2586 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2587 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2588 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2589 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2590 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2593 static struct ast_cli_entry cli_asterisk[] = {
2594 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2595 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2596 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2597 AST_CLI_DEFINE(handle_version, "Display version info"),
2598 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2599 #if !defined(LOW_MEMORY)
2600 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2601 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2602 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2604 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2605 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2606 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2607 #endif /* ! LOW_MEMORY */
2610 static void send_rasterisk_connect_commands(void)
2615 * Tell the server asterisk instance about the verbose level
2616 * initially desired.
2618 if (option_verbose) {
2619 snprintf(buf, sizeof(buf), "core set verbose atleast %d silent", option_verbose);
2620 fdsend(ast_consock, buf);
2624 snprintf(buf, sizeof(buf), "core set debug atleast %d", option_debug);
2625 fdsend(ast_consock, buf);
2628 if (!ast_opt_mute) {
2629 fdsend(ast_consock, "logger mute silent");
2631 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2635 static int ast_el_read_char(EditLine *editline, char *cp)
2639 struct pollfd fds[2];
2642 #define EL_BUF_SIZE 512
2643 char buf[EL_BUF_SIZE];
2647 fds[0].fd = ast_consock;
2648 fds[0].events = POLLIN;
2649 if (!ast_opt_exec) {
2650 fds[1].fd = STDIN_FILENO;
2651 fds[1].events = POLLIN;
2654 res = ast_poll(fds, max, -1);
2656 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2660 fprintf(stderr, "poll failed: %s\n", strerror(errno));
2664 if (!ast_opt_exec && fds[1].revents) {
2665 num_read = read(STDIN_FILENO, cp, 1);
2672 if (fds[0].revents) {
2673 res = read(ast_consock, buf, sizeof(buf) - 1);
2674 /* if the remote side disappears exit */
2676 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2677 if (!ast_opt_reconnect) {
2678 quit_handler(0, SHUTDOWN_FAST, 0);
2681 int reconnects_per_second = 20;
2682 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2683 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2684 if (ast_tryconnect()) {
2685 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2686 printf("%s", term_quit());
2688 send_rasterisk_connect_commands();
2691 usleep(1000000 / reconnects_per_second);
2693 if (tries >= 30 * reconnects_per_second) {
2694 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2695 quit_handler(0, SHUTDOWN_FAST, 0);
2703 /* Write over the CLI prompt */
2704 if (!ast_opt_exec && !lastpos) {
2705 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2709 console_print(buf, 0);
2711 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2723 static struct ast_str *prompt = NULL;
2725 static char *cli_prompt(EditLine *editline)
2730 static int cli_prompt_changes = 0;
2734 if (prompt == NULL) {
2735 prompt = ast_str_create(100);
2736 } else if (!cli_prompt_changes) {
2737 return ast_str_buffer(prompt);
2739 ast_str_reset(prompt);
2742 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2744 struct timeval ts = ast_tvnow();
2745 while (*t != '\0') {
2747 char hostname[MAXHOSTNAMELEN] = "";
2749 struct ast_tm tm = { 0, };
2750 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2754 case 'C': /* color */
2756 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2757 ast_term_color_code(&prompt, fgcolor, bgcolor);
2759 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2760 ast_term_color_code(&prompt, fgcolor, 0);
2764 /* If the color has been reset correctly, then there's no need to reset it later */
2765 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2767 case 'd': /* date */
2768 if (ast_localtime(&ts, &tm, NULL)) {
2769 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2770 ast_str_append(&prompt, 0, "%s", tmp);
2771 cli_prompt_changes++;
2774 case 'g': /* group */
2775 if ((gr = getgrgid(getgid()))) {
2776 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2779 case 'h': /* hostname */
2780 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2781 ast_str_append(&prompt, 0, "%s", hostname);
2783 ast_str_append(&prompt, 0, "%s", "localhost");
2786 case 'H': /* short hostname */
2787 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2789 if ((dotptr = strchr(hostname, '.'))) {
2792 ast_str_append(&prompt, 0, "%s", hostname);
2794 ast_str_append(&prompt, 0, "%s", "localhost");
2797 #ifdef HAVE_GETLOADAVG
2798 case 'l': /* load avg */
2800 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2802 getloadavg(list, 3);
2803 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2804 cli_prompt_changes++;
2808 case 's': /* Asterisk system name (from asterisk.conf) */
2809 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2811 case 't': /* time */
2812 if (ast_localtime(&ts, &tm, NULL)) {
2813 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2814 ast_str_append(&prompt, 0, "%s", tmp);
2815 cli_prompt_changes++;
2818 case 'u': /* username */
2819 if ((pw = getpwuid(getuid()))) {
2820 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2823 case '#': /* process console or remote? */
2824 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2826 case '%': /* literal % */
2827 ast_str_append(&prompt, 0, "%c", '%');
2829 case '\0': /* % is last character - prevent bug */
2834 ast_str_append(&prompt, 0, "%c", *t);
2839 /* Force colors back to normal at end */
2840 ast_term_color_code(&prompt, 0, 0);
2843 ast_str_set(&prompt, 0, "%s%s",
2844 remotehostname ? remotehostname : "",
2848 return ast_str_buffer(prompt);
2851 static void destroy_match_list(char **match_list, int matches)
2856 for (idx = 0; idx < matches; ++idx) {
2857 ast_free(match_list[idx]);
2859 ast_free(match_list);
2863 static char **ast_el_strtoarr(char *buf)
2866 char **match_list = NULL;
2868 size_t match_list_len = 1;
2871 while ((retstr = strsep(&buf, " "))) {
2872 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) {
2875 if (matches + 1 >= match_list_len) {
2876 match_list_len <<= 1;
2877 new_list = ast_realloc(match_list, match_list_len * sizeof(char *));
2879 destroy_match_list(match_list, matches);
2882 match_list = new_list;
2885 retstr = ast_strdup(retstr);
2887 destroy_match_list(match_list, matches);
2890 match_list[matches++] = retstr;
2897 if (matches >= match_list_len) {
2898 new_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *));
2900 destroy_match_list(match_list, matches);
2903 match_list = new_list;
2906 match_list[matches] = NULL;
2911 static int ast_el_sort_compare(const void *i1, const void *i2)
2915 s1 = ((char **)i1)[0];
2916 s2 = ((char **)i2)[0];
2918 return strcasecmp(s1, s2);
2921 static int ast_cli_display_match_list(char **matches, int len, int max)
2923 int i, idx, limit, count;
2924 int screenwidth = 0;
2925 int numoutput = 0, numoutputline = 0;
2927 screenwidth = ast_get_termcols(STDOUT_FILENO);
2929 /* find out how many entries can be put on one line, with two spaces between strings */
2930 limit = screenwidth / (max + 2);
2934 /* how many lines of output */
2935 count = len / limit;
2936 if (count * limit < len)
2941 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2943 for (; count > 0; count--) {
2945 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2947 /* Don't print dupes */
2948 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2950 ast_free(matches[idx]);
2951 matches[idx] = NULL;
2957 fprintf(stdout, "%-*s ", max, matches[idx]);
2958 ast_free(matches[idx]);
2959 matches[idx] = NULL;
2961 if (numoutputline > 0)
2962 fprintf(stdout, "\n");
2969 static char *cli_complete(EditLine *editline, int ch)
2975 int retval = CC_ERROR;
2976 char buf[2048], savechr;
2979 LineInfo *lf = (LineInfo *)el_line(editline);
2981 savechr = *(char *)lf->cursor;
2982 *(char *)lf->cursor = '\0';
2983 ptr = (char *)lf->cursor;
2985 while (ptr > lf->buffer) {
2986 if (isspace(*ptr)) {
2994 len = lf->cursor - ptr;
2996 if (ast_opt_remote) {
2997 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2998 fdsend(ast_consock, buf);
2999 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
3000 return (char*)(CC_ERROR);
3003 nummatches = atoi(buf);
3005 if (nummatches > 0) {
3008 int mlen = 0, maxmbuf = 2048;
3010 /* Start with a 2048 byte buffer */
3011 if (!(mbuf = ast_malloc(maxmbuf))) {
3012 *((char *) lf->cursor) = savechr;
3013 return (char *)(CC_ERROR);
3015 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
3016 fdsend(ast_consock, buf);
3019 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
3020 if (mlen + 1024 > maxmbuf) {
3021 /* Every step increment buffer 1024 bytes */
3023 new_mbuf = ast_realloc(mbuf, maxmbuf);
3026 *((char *) lf->cursor) = savechr;
3027 return (char *)(CC_ERROR);
3031 /* Only read 1024 bytes at a time */
3032 res = read(ast_consock, mbuf + mlen, 1024);
3038 matches = ast_el_strtoarr(mbuf);
3041 matches = (char **) NULL;
3043 char **p, *oldbuf=NULL;
3045 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
3046 for (p = matches; p && *p; p++) {
3047 if (!oldbuf || strcmp(*p,oldbuf))
3055 int matches_num, maxlen, match_len;
3057 if (matches[0][0] != '\0') {
3058 el_deletestr(editline, (int) len);
3059 el_insertstr(editline, matches[0]);
3060 retval = CC_REFRESH;
3063 if (nummatches == 1) {
3064 /* Found an exact match */
3065 el_insertstr(editline, " ");
3066 retval = CC_REFRESH;
3068 /* Must be more than one match */
3069 for (i = 1, maxlen = 0; matches[i]; i++) {
3070 match_len = strlen(matches[i]);
3071 if (match_len > maxlen)
3074 matches_num = i - 1;
3075 if (matches_num >1) {
3076 fprintf(stdout, "\n");
3077 ast_cli_display_match_list(matches, nummatches, maxlen);
3078 retval = CC_REDISPLAY;
3080 el_insertstr(editline," ");
3081 retval = CC_REFRESH;
3084 for (i = 0; matches[i]; i++)
3085 ast_free(matches[i]);
3089 *((char *) lf->cursor) = savechr;
3091 return (char *)(long)retval;
3094 static int ast_el_initialize(void)
3097 char *editor, *editrc = getenv("EDITRC");
3099 if (!(editor = getenv("AST_EDITMODE"))) {
3100 if (!(editor = getenv("AST_EDITOR"))) {
3107 if (el_hist != NULL)
3108 history_end(el_hist);
3110 el = el_init("asterisk", stdin, stdout, stderr);
3111 el_set(el, EL_PROMPT, cli_prompt);
3113 el_set(el, EL_EDITMODE, 1);
3114 el_set(el, EL_EDITOR, editor);
3115 el_hist = history_init();
3116 if (!el || !el_hist)
3119 /* setup history with 100 entries */
3120 history(el_hist, &ev, H_SETSIZE, 100);
3122 el_set(el, EL_HIST, history, el_hist);
3124 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
3125 /* Bind <tab> to command completion */
3126 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
3127 /* Bind ? to command completion */
3128 el_set(el, EL_BIND, "?", "ed-complete", NULL);
3129 /* Bind ^D to redisplay */
3130 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
3131 /* Bind Delete to delete char left */
3132 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
3133 /* Bind Home and End to move to line start and end */
3134 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3135 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3136 /* Bind C-left and C-right to move by word (not all terminals) */
3137 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
3138 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
3141 el_source(el, editrc);
3147 #define MAX_HISTORY_COMMAND_LENGTH 256
3149 static int ast_el_add_history(char *buf)
3154 if (el_hist == NULL || el == NULL) {
3155 ast_el_initialize();
3157 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1)) {
3161 stripped_buf = ast_strip(ast_strdupa(buf));
3163 /* HISTCONTROL=ignoredups */
3164 if (!history(el_hist, &ev, H_FIRST) && strcmp(ev.str, stripped_buf) == 0) {
3168 return history(el_hist, &ev, H_ENTER, stripped_buf);
3171 static int ast_el_write_history(char *filename)
3175 if (el_hist == NULL || el == NULL)
3176 ast_el_initialize();
3178 return (history(el_hist, &ev, H_SAVE, filename));
3181 static int ast_el_read_history(char *filename)
3185 if (el_hist == NULL || el == NULL) {
3186 ast_el_initialize();
3189 return history(el_hist, &ev, H_LOAD, filename);
3192 static void ast_remotecontrol(char *data)
3196 char filename[80] = "";
3201 char *stringp = NULL;
3206 memset(&sig_flags, 0, sizeof(sig_flags));
3207 signal(SIGINT, __remote_quit_handler);
3208 signal(SIGTERM, __remote_quit_handler);
3209 signal(SIGHUP, __remote_quit_handler);
3211 if (read(ast_consock, buf, sizeof(buf) - 1) < 0) {
3212 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3216 char prefix[] = "cli quit after ";
3217 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3218 sprintf(tmp, "%s%s", prefix, data);
3219 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3220 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3221 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3227 hostname = strsep(&stringp, "/");
3228 cpid = strsep(&stringp, "/");
3229 version = strsep(&stringp, "\n");
3231 version = "<Version Unknown>";
3233 strsep(&stringp, ".");
3239 send_rasterisk_connect_commands();
3242 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
3243 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3245 fds.fd = ast_consock;
3246 fds.events = POLLIN;
3249 while (ast_poll(&fds, 1, 60000) > 0) {
3250 char buffer[512] = "", *curline = buffer, *nextline;
3251 int not_written = 1;
3253 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3257 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3262 prev_linefull = linefull;
3263 if ((nextline = strchr(curline, '\n'))) {
3268 nextline = strchr(curline, '\0');
3271 /* Skip verbose lines */
3272 /* Prev line full? | Line is verbose | Last line verbose? | Print
3273 * TRUE | TRUE* | TRUE | FALSE
3274 * TRUE | TRUE* | FALSE | FALSE
3275 * TRUE | FALSE* | TRUE | TRUE
3276 * TRUE | FALSE* | FALSE | TRUE
3277 * FALSE | TRUE | TRUE* | FALSE
3278 * FALSE | TRUE | FALSE* | TRUE
3279 * FALSE | FALSE | TRUE* | FALSE
3280 * FALSE | FALSE | FALSE* | TRUE
3282 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3283 prev_line_verbose = 0;
3285 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3286 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3289 prev_line_verbose = 1;
3292 } while (!ast_strlen_zero(curline));
3294 /* No non-verbose output in 60 seconds. */
3302 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3303 remotehostname = hostname;
3305 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3306 if (el_hist == NULL || el == NULL)
3307 ast_el_initialize();
3309 el_set(el, EL_GETCFN, ast_el_read_char);
3311 if (!ast_strlen_zero(filename))
3312 ast_el_read_history(filename);
3315 ebuf = (char *)el_gets(el, &num);
3317 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3321 if (!ebuf && write(1, "", 1) < 0)
3324 if (!ast_strlen_zero(ebuf)) {
3325 if (ebuf[strlen(ebuf)-1] == '\n')
3326 ebuf[strlen(ebuf)-1] = '\0';
3327 if (!remoteconsolehandler(ebuf)) {
3328 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3330 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3336 printf("\nDisconnected from Asterisk server\n");
3339 static int show_version(void)
3341 printf("Asterisk %s\n", ast_get_version());
3345 static int show_cli_help(void)
3347 printf("Asterisk %s, Copyright (C) 1999 - 2014, Digium, Inc. and others.\n", ast_get_version());
3348 printf("Usage: asterisk [OPTIONS]\n");
3349 printf("Valid Options:\n");
3350 printf(" -V Display version number and exit\n");
3351 printf(" -C <configfile> Use an alternate configuration file\n");
3352 printf(" -G <group> Run as a group other than the caller\n");
3353 printf(" -U <user> Run as a user other than the caller\n");
3354 printf(" -c Provide console CLI\n");
3355 printf(" -d Enable extra debugging\n");
3356 #if HAVE_WORKING_FORK
3357 printf(" -f Do not fork\n");
3358 printf(" -F Always fork\n");
3360 printf(" -g Dump core in case of a crash\n");
3361 printf(" -h This help screen\n");
3362 printf(" -i Initialize crypto keys at startup\n");
3363 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
3364 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
3365 printf(" -m Mute debugging and console output on the console\n");
3366 printf(" -n Disable console colorization\n");
3367 printf(" -p Run as pseudo-realtime thread\n");
3368 printf(" -q Quiet mode (suppress output)\n");
3369 printf(" -r Connect to Asterisk on this machine\n");
3370 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
3371 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
3372 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
3373 printf(" belong after they are done\n");
3374 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3375 printf(" of output to the CLI\n");
3376 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
3377 printf(" -x <cmd> Execute command <cmd> (implies -r)\n");
3378 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
3379 printf(" -W Adjust terminal colors to compensate for a light background\n");
3384 static void ast_readconfig(void)
3386 struct ast_config *cfg;
3387 struct ast_variable *v;
3388 char *config = DEFAULT_CONFIG_FILE;
3389 char hostname[MAXHOSTNAMELEN] = "";
3390 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3392 unsigned int dbdir:1;
3393 unsigned int keydir:1;
3395 /* Default to false for security */
3396 int live_dangerously = 0;
3398 /* Set default value */
3399 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3401 if (ast_opt_override_config) {
3402 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3403 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3404 fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3407 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3410 /* init with buildtime config */
3411 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3412 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3413 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3414 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3415 snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", cfg_paths.spool_dir);
3416 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3417 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3418 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3419 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3420 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3421 ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3422 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3423 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3424 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3425 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3428 /* The REF_DEBUG compiler flag is now only used to enable refdebug by default.
3429 * Support for debugging reference counts is always compiled in. */
3430 ast_set2_flag(&ast_options, 1, AST_OPT_FLAG_REF_DEBUG);
3433 ast_set_default_eid(&ast_eid_default);
3435 /* no asterisk.conf? no problem, use buildtime config! */
3436 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3440 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3441 if (!strcasecmp(v->name, "astctlpermissions"))
3442 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3443 else if (!strcasecmp(v->name, "astctlowner"))
3444 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3445 else if (!strcasecmp(v->name, "astctlgroup"))
3446 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3447 else if (!strcasecmp(v->name, "astctl"))
3448 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3451 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3452 if (!strcasecmp(v->name, "astetcdir")) {
3453 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3454 } else if (!strcasecmp(v->name, "astspooldir")) {
3455 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3456 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3457 snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", v->value);
3458 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3459 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3461 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3462 } else if (!strcasecmp(v->name, "astdbdir")) {
3463 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3465 } else if (!strcasecmp(v->name, "astdatadir")) {
3466 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3468 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3469 } else if (!strcasecmp(v->name, "astkeydir")) {
3470 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3472 } else if (!strcasecmp(v->name, "astlogdir")) {
3473 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3474 } else if (!strcasecmp(v->name, "astagidir")) {
3475 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3476 } else if (!strcasecmp(v->name, "astrundir")) {
3477 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3478 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3479 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3480 } else if (!strcasecmp(v->name, "astmoddir")) {
3481 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3482 } else if (!strcasecmp(v->name, "astsbindir")) {
3483 ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3487 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3488 /* verbose level (-v at startup) */
3489 if (!strcasecmp(v->name, "verbose")) {
3490 option_verbose = atoi(v->value);
3491 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3492 } else if (!strcasecmp(v->name, "timestamp")) {
3493 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3494 /* whether or not to support #exec in config files */
3495 } else if (!strcasecmp(v->name, "execincludes")) {
3496 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3497 /* debug level (-d at startup) */
3498 } else if (!strcasecmp(v->name, "debug")) {
3500 if (sscanf(v->value, "%30d", &option_debug) != 1) {
3501 option_debug = ast_true(v->value);
3503 } else if (!strcasecmp(v->name, "refdebug")) {
3504 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_REF_DEBUG);
3505 #if HAVE_WORKING_FORK
3506 /* Disable forking (-f at startup) */
3507 } else if (!strcasecmp(v->name, "nofork")) {
3508 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3509 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3510 } else if (!strcasecmp(v->name, "alwaysfork")) {
3511 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3513 /* Run quietly (-q at startup ) */
3514 } else if (!strcasecmp(v->name, "quiet")) {
3515 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3516 /* Run as console (-c at startup, implies nofork) */
3517 } else if (!strcasecmp(v->name, "console")) {
3518 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3519 /* Run with high priority if the O/S permits (-p at startup) */
3520 } else if (!strcasecmp(v->name, "highpriority")) {
3521 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3522 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3523 } else if (!strcasecmp(v->name, "initcrypto")) {
3524 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3525 /* Disable ANSI colors for console (-c at startup) */
3526 } else if (!strcasecmp(v->name, "nocolor")) {
3527 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3528 /* Disable some usage warnings for picky people :p */
3529 } else if (!strcasecmp(v->name, "dontwarn")) {
3530 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3531 /* Dump core in case of crash (-g) */
3532 } else if (!strcasecmp(v->name, "dumpcore")) {
3533 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3534 /* Cache recorded sound files to another directory during recording */
3535 } else if (!strcasecmp(v->name, "cache_record_files")) {
3536 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3537 /* Specify cache directory */
3538 } else if (!strcasecmp(v->name, "record_cache_dir")) {
3539 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3540 /* Build transcode paths via SLINEAR, instead of directly */
3541 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3542 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3543 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3544 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3545 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3546 /* Enable internal timing */
3547 } else if (!strcasecmp(v->name, "internal_timing")) {
3548 if (!ast_opt_remote) {
3550 "NOTICE: The internal_timing option is no longer needed.\n"
3551 " It will always be enabled if you have a timing module loaded.\n");
3553 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3554 if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3555 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3557 } else if (!strcasecmp(v->name, "maxcalls")) {
3558 if ((sscanf(v->value, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) {
3559 ast_option_maxcalls = 0;
3561 } else if (!strcasecmp(v->name, "maxload")) {
3564 if (getloadavg(test, 1) == -1) {
3565 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3566 ast_option_maxload = 0.0;
3567 } else if ((sscanf(v->value, "%30lf", &ast_option_maxload) != 1) || (ast_option_maxload < 0.0)) {
3568 ast_option_maxload = 0.0;
3570 /* Set the maximum amount of open files */
3571 } else if (!strcasecmp(v->name, "maxfiles")) {
3572 ast_option_maxfiles = atoi(v->value);
3573 set_ulimit(ast_option_maxfiles);
3574 /* What user to run as */
3575 } else if (!strcasecmp(v->name, "runuser")) {
3576 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3577 /* What group to run as */
3578 } else if (!strcasecmp(v->name, "rungroup")) {
3579 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3580 } else if (!strcasecmp(v->name, "systemname")) {
3581 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3582 } else if (!strcasecmp(v->name, "autosystemname")) {
3583 if (ast_true(v->value)) {
3584 if (!gethostname(hostname, sizeof(hostname) - 1))
3585 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3587 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3588 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3590 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3593 } else if (!strcasecmp(v->name, "languageprefix")) {
3594 ast_language_is_prefix = ast_true(v->value);
3595 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3596 ast_copy_string(ast_defaultlanguage, v->value, MAX_LANGUAGE);
3597 } else if (!strcasecmp(v->name, "lockmode")) {
3598 if (!strcasecmp(v->value, "lockfile")) {
3599 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3600 } else if (!strcasecmp(v->value, "flock")) {
3601 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3603 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3604 "defaulting to 'lockfile'\n", v->value);
3605 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3607 #if defined(HAVE_SYSINFO)
3608 } else if (!strcasecmp(v->name, "minmemfree")) {
3609 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
3610 * if the amount of free memory falls below this watermark */
3611 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3612 option_minmemfree = 0;
3615 } else if (!strcasecmp(v->name, "entityid")) {
3616 struct ast_eid tmp_eid;
3617 if (!ast_str_to_eid(&tmp_eid, v->value)) {
3618 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3619 ast_eid_default = tmp_eid;
3621 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3622 } else if (!strcasecmp(v->name, "lightbackground")) {
3623 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3624 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3625 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3626 } else if (!strcasecmp(v->name, "hideconnect")) {
3627 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3628 } else if (!strcasecmp(v->name, "lockconfdir")) {
3629 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3630 } else if (!strcasecmp(v->name, "stdexten")) {
3631 /* Choose how to invoke the extensions.conf stdexten */
3632 if (!strcasecmp(v->value, "gosub")) {
3633 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3634 } else if (!strcasecmp(v->value, "macro")) {
3635 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3637 ast_log(LOG_WARNING,
3638 "'%s' is not a valid setting for the stdexten option, defaulting to&n