2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2012, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
22 * \mainpage Asterisk -- The Open Source Telephony Project
26 * This documentation created by the Doxygen project clearly explains the
27 * internals of the Asterisk software. This documentation contains basic
28 * examples, developer documentation, support information, and information
31 * \section community Community
32 * Asterisk is a big project and has a busy community. Look at the
33 * resources for questions and stick around to help answer questions.
34 * \li \ref asterisk_community_resources
36 * \par Developer Documentation for Asterisk
38 * This is the main developer documentation for Asterisk. It is
39 * generated by running "make progdocs" from the Asterisk source tree.
41 * In addition to the information available on the Asterisk source code,
42 * please see the appendices for information on coding guidelines,
43 * release management, commit policies, and more.
45 * \arg \ref AsteriskArchitecture
47 * \par Additional documentation
50 * \arg \ref configuration_file
52 * \section copyright Copyright and Author
54 * Copyright (C) 1999 - 2012, Digium, Inc.
55 * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
56 * of <a href="http://www.digium.com">Digium, Inc</a>.
58 * \author Mark Spencer <markster@digium.com>
60 * See http://www.asterisk.org for more information about
61 * the Asterisk project. Please do not directly contact
62 * any of the maintainers of this project for assistance;
63 * the project provides a web site, mailing lists, and IRC
64 * channels for your use.
69 * \page asterisk_community_resources Asterisk Community Resources
71 * \li http://www.asterisk.org Asterisk Homepage
72 * \li http://wiki.asterisk.org Asterisk Wiki
76 * All lists: http://lists.digium.com/mailman/listinfo
77 * \li aadk-commits SVN commits to the AADK repository
78 * \li asterisk-addons-commits SVN commits to the Asterisk addons project
79 * \li asterisk-announce [no description available]
80 * \li asterisk-biz Commercial and Business-Oriented Asterisk Discussion
81 * \li Asterisk-BSD Asterisk on BSD discussion
82 * \li asterisk-bugs [no description available]
83 * \li asterisk-commits SVN commits to the Asterisk project
84 * \li asterisk-dev Asterisk Developers Mailing List
85 * \li asterisk-doc Discussions regarding The Asterisk Documentation Project
86 * \li asterisk-embedded Asterisk Embedded Development
87 * \li asterisk-gui Asterisk GUI project discussion
88 * \li asterisk-gui-commits SVN commits to the Asterisk-GUI project
89 * \li asterisk-ha-clustering Asterisk High Availability and Clustering List - Non-Commercial Discussion
90 * \li Asterisk-i18n Discussion of Asterisk internationalization
91 * \li asterisk-r2 [no description available]
92 * \li asterisk-scf-commits Commits to the Asterisk SCF project code repositories
93 * \li asterisk-scf-committee Asterisk SCF Steering Committee discussions
94 * \li asterisk-scf-dev Asterisk SCF Developers Mailing List
95 * \li asterisk-scf-wiki-changes Changes to the Asterisk SCF space on wiki.asterisk.org
96 * \li asterisk-security Asterisk Security Discussion
97 * \li asterisk-speech-rec Use of speech recognition in Asterisk
98 * \li asterisk-ss7 [no description available]
99 * \li asterisk-users Asterisk Users Mailing List - Non-Commercial Discussion
100 * \li asterisk-video Development discussion of video media support in Asterisk
101 * \li asterisk-wiki-changes Changes to the Asterisk space on wiki.asterisk.org
102 * \li asterisknow AsteriskNOW Discussion
103 * \li dahdi-commits SVN commits to the DAHDI project
104 * \li digium-announce Digium Product Announcements
105 * \li Dundi Distributed Universal Number Discovery
106 * \li libiax2-commits SVN commits to the libiax2 project
107 * \li libpri-commits SVN commits to the libpri project
108 * \li libss7-commits SVN commits to the libss7 project
109 * \li svn-commits SVN commits to the Digium repositories
110 * \li Test-results Results from automated testing
111 * \li thirdparty-commits SVN commits to the Digium third-party software repository
112 * \li zaptel-commits SVN commits to the Zaptel project
115 * \li Forums are located at http://forums.asterisk.org/
119 * Use http://www.freenode.net IRC server to connect with Asterisk
120 * developers and users in realtime.
122 * \li \verbatim #asterisk \endverbatim Asterisk Users Room
123 * \li \verbatim #asterisk-dev \endverbatim Asterisk Developers Room
127 * If you would like to add a resource to this list please create an issue
128 * on the issue tracker with a patch.
132 * \brief Top level source file for Asterisk - the Open Source PBX.
133 * Implementation of PBX core functions and CLI interface.
137 * \li The Asterisk core uses the configuration file \ref asterisk.conf
138 * \addtogroup configuration_file
141 /*! \page asterisk.conf asterisk.conf
142 * \verbinclude asterisk.conf.sample
146 <support_level>core</support_level>
149 #include "asterisk.h"
151 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
153 #include "asterisk/_private.h"
155 #undef sched_setscheduler
157 #include <sys/time.h>
162 #include <sys/wait.h>
164 #include <sys/resource.h>
167 #include <sys/stat.h>
168 #if defined(HAVE_SYSINFO)
169 #include <sys/sysinfo.h>
170 #elif defined(HAVE_SYSCTL)
171 #include <sys/param.h>
172 #include <sys/sysctl.h>
173 #if !defined(__OpenBSD__)
174 #include <sys/vmmeter.h>
175 #if defined(__FreeBSD__)
176 #include <vm/vm_param.h>
179 #if defined(HAVE_SWAPCTL)
180 #include <sys/swap.h>
184 #include <histedit.h>
187 int daemon(int, int); /* defined in libresolv of all places */
188 #include <sys/loadavg.h>
192 #include <sys/prctl.h>
194 #include <sys/capability.h>
195 #endif /* HAVE_CAP */
198 /* we define here the variables so to better agree on the prototype */
199 #include "asterisk/paths.h"
200 #include "asterisk/network.h"
201 #include "asterisk/cli.h"
202 #include "asterisk/channel.h"
203 #include "asterisk/translate.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"
241 #include "../defaults.h"
247 #define AF_LOCAL AF_UNIX
248 #define PF_LOCAL PF_UNIX
251 #define AST_MAX_CONNECTS 128
254 /*! Default minimum DTMF digit length - 80ms */
255 #define AST_MIN_DTMF_DURATION 80
258 /*! \brief Welcome message when starting a CLI interface */
259 #define WELCOME_MESSAGE \
260 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
261 "Created by Mark Spencer <markster@digium.com>\n" \
262 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
263 "This is free software, with components licensed under the GNU General Public\n" \
264 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
265 "certain conditions. Type 'core show license' for details.\n" \
266 "=========================================================================\n", ast_get_version()) \
268 /*! \defgroup main_options Main Configuration Options
269 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
270 * \arg \ref Config_ast "asterisk.conf"
271 * \note Some of them can be changed in the CLI
275 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
276 struct ast_flags ast_compat = { 0 };
278 int option_verbose; /*!< Verbosity level */
279 int option_debug; /*!< Debug level */
280 double option_maxload; /*!< Max load avg on system */
281 int option_maxcalls; /*!< Max number of active calls */
282 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
283 unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */
284 #if defined(HAVE_SYSINFO)
285 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
290 struct ast_eid ast_eid_default;
292 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
293 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
295 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
296 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
299 int fd; /*!< File descriptor */
300 int p[2]; /*!< Pipe */
301 pthread_t t; /*!< Thread of handler */
302 int mute; /*!< Is the console muted for logs */
303 int uid; /*!< Remote user ID. */
304 int gid; /*!< Remote group ID. */
305 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
310 AST_RWLIST_ENTRY(ast_atexit) list;
313 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
315 struct timeval ast_startuptime;
316 struct timeval ast_lastreloadtime;
318 static History *el_hist;
320 static char *remotehostname;
322 struct console consoles[AST_MAX_CONNECTS];
324 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
326 static int ast_el_add_history(char *);
327 static int ast_el_read_history(char *);
328 static int ast_el_write_history(char *);
331 char config_dir[PATH_MAX];
332 char module_dir[PATH_MAX];
333 char spool_dir[PATH_MAX];
334 char monitor_dir[PATH_MAX];
335 char var_dir[PATH_MAX];
336 char data_dir[PATH_MAX];
337 char log_dir[PATH_MAX];
338 char agi_dir[PATH_MAX];
339 char run_dir[PATH_MAX];
340 char key_dir[PATH_MAX];
342 char config_file[PATH_MAX];
343 char db_path[PATH_MAX];
344 char sbin_dir[PATH_MAX];
345 char pid_path[PATH_MAX];
346 char socket_path[PATH_MAX];
347 char run_user[PATH_MAX];
348 char run_group[PATH_MAX];
349 char system_name[128];
352 static struct _cfg_paths cfg_paths;
354 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
355 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
356 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
357 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
358 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
359 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
360 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
361 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
362 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
363 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
364 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
365 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
367 const char *ast_config_AST_DB = cfg_paths.db_path;
368 const char *ast_config_AST_PID = cfg_paths.pid_path;
369 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
370 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
371 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
372 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
374 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
375 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
376 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
377 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
379 extern unsigned int ast_FD_SETSIZE;
381 static char *_argv[256];
383 NOT_SHUTTING_DOWN = -2,
385 /* Valid values for quit_handler niceness below: */
391 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
392 static int restartnow;
393 static pthread_t consolethread = AST_PTHREADT_NULL;
394 static pthread_t mon_sig_flags;
395 static int canary_pid = 0;
396 static char canary_filename[128];
398 static char randompool[256];
400 static int sig_alert_pipe[2] = { -1, -1 };
402 unsigned int need_reload:1;
403 unsigned int need_quit:1;
404 unsigned int need_quit_handler:1;
407 #if !defined(LOW_MEMORY)
408 struct file_version {
409 AST_RWLIST_ENTRY(file_version) list;
414 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
416 void ast_register_file_version(const char *file, const char *version)
418 struct file_version *new;
420 size_t version_length;
422 work = ast_strdupa(version);
423 work = ast_strip(ast_strip_quoted(work, "$", "$"));
424 version_length = strlen(work) + 1;
426 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
430 new->version = (char *) new + sizeof(*new);
431 memcpy(new->version, work, version_length);
432 AST_RWLIST_WRLOCK(&file_versions);
433 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
434 AST_RWLIST_UNLOCK(&file_versions);
437 void ast_unregister_file_version(const char *file)
439 struct file_version *find;
441 AST_RWLIST_WRLOCK(&file_versions);
442 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
443 if (!strcasecmp(find->file, file)) {
444 AST_RWLIST_REMOVE_CURRENT(list);
448 AST_RWLIST_TRAVERSE_SAFE_END;
449 AST_RWLIST_UNLOCK(&file_versions);
455 char *ast_complete_source_filename(const char *partial, int n)
457 struct file_version *find;
458 size_t len = strlen(partial);
462 AST_RWLIST_RDLOCK(&file_versions);
463 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
464 if (!strncasecmp(find->file, partial, len) && ++count > n) {
465 res = ast_strdup(find->file);
469 AST_RWLIST_UNLOCK(&file_versions);
473 /*! \brief Find version for given module name */
474 const char *ast_file_version_find(const char *file)
476 struct file_version *iterator;
478 AST_RWLIST_WRLOCK(&file_versions);
479 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
480 if (!strcasecmp(iterator->file, file))
483 AST_RWLIST_UNLOCK(&file_versions);
485 return iterator->version;
489 struct thread_list_t {
490 AST_RWLIST_ENTRY(thread_list_t) list;
496 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
498 void ast_register_thread(char *name)
500 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
504 new->id = pthread_self();
505 new->lwp = ast_get_tid();
506 new->name = name; /* steal the allocated memory for the thread name */
507 AST_RWLIST_WRLOCK(&thread_list);
508 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
509 AST_RWLIST_UNLOCK(&thread_list);
512 void ast_unregister_thread(void *id)
514 struct thread_list_t *x;
516 AST_RWLIST_WRLOCK(&thread_list);
517 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
518 if ((void *) x->id == id) {
519 AST_RWLIST_REMOVE_CURRENT(list);
523 AST_RWLIST_TRAVERSE_SAFE_END;
524 AST_RWLIST_UNLOCK(&thread_list);
531 /*! \brief Give an overview of core settings */
532 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
540 e->command = "core show settings";
541 e->usage = "Usage: core show settings\n"
542 " Show core misc settings";
548 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
550 ast_cli(a->fd, "\nPBX Core settings\n");
551 ast_cli(a->fd, "-----------------\n");
552 ast_cli(a->fd, " Version: %s\n", ast_get_version());
553 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
555 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
557 ast_cli(a->fd, " Maximum calls: Not set\n");
559 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
561 ast_cli(a->fd, " Maximum open file handles: Not set\n");
562 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
563 ast_cli(a->fd, " Debug level: %d\n", option_debug);
564 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
565 #if defined(HAVE_SYSINFO)
566 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
568 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
569 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
570 ast_cli(a->fd, " Startup time: %s\n", buf);
572 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
573 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
574 ast_cli(a->fd, " Last reload time: %s\n", buf);
576 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);
577 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
578 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
579 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
580 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
581 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
582 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
583 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
584 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
585 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
586 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
587 ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
589 ast_cli(a->fd, "\n* Subsystems\n");
590 ast_cli(a->fd, " -------------\n");
591 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
592 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
593 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
594 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
596 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
598 ast_cli(a->fd, "\n* Directories\n");
599 ast_cli(a->fd, " -------------\n");
600 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
601 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
602 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
603 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
604 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
605 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
606 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
607 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
608 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
609 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
610 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
611 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
612 ast_cli(a->fd, "\n\n");
616 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
619 struct thread_list_t *cur;
622 e->command = "core show threads";
624 "Usage: core show threads\n"
625 " List threads currently active in the system.\n";
631 AST_RWLIST_RDLOCK(&thread_list);
632 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
633 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
636 AST_RWLIST_UNLOCK(&thread_list);
637 ast_cli(a->fd, "%d threads listed.\n", count);
641 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
643 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
644 * to be based on the new swapctl(2) system call.
646 static int swapmode(int *used, int *total)
648 struct swapent *swdev;
649 int nswap, rnswap, i;
651 nswap = swapctl(SWAP_NSWAP, 0, 0);
655 swdev = ast_calloc(nswap, sizeof(*swdev));
659 rnswap = swapctl(SWAP_STATS, swdev, nswap);
665 /* if rnswap != nswap, then what? */
667 /* Total things up */
669 for (i = 0; i < nswap; i++) {
670 if (swdev[i].se_flags & SWF_ENABLE) {
671 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
672 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
678 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
679 static int swapmode(int *used, int *total)
686 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
687 /*! \brief Give an overview of system statistics */
688 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
690 uint64_t physmem, freeram;
691 uint64_t freeswap = 0;
695 #if defined(HAVE_SYSINFO)
696 struct sysinfo sys_info;
698 uptime = sys_info.uptime / 3600;
699 physmem = sys_info.totalram * sys_info.mem_unit;
700 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
701 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
702 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
703 nprocs = sys_info.procs;
704 #elif defined(HAVE_SYSCTL)
705 static int pageshift;
706 struct vmtotal vmtotal;
707 struct timeval boottime;
709 int mib[2], pagesize, usedswap = 0;
711 /* calculate the uptime by looking at boottime */
714 mib[1] = KERN_BOOTTIME;
715 len = sizeof(boottime);
716 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
717 uptime = now - boottime.tv_sec;
719 uptime = uptime/3600;
720 /* grab total physical memory */
722 #if defined(HW_PHYSMEM64)
723 mib[1] = HW_PHYSMEM64;
727 len = sizeof(physmem);
728 sysctl(mib, 2, &physmem, &len, NULL, 0);
730 pagesize = getpagesize();
732 while (pagesize > 1) {
737 /* we only need the amount of log(2)1024 for our conversion */
743 len = sizeof(vmtotal);
744 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
745 freeram = (vmtotal.t_free << pageshift);
746 /* generate swap usage and totals */
747 swapmode(&usedswap, &totalswap);
748 freeswap = (totalswap - usedswap);
749 /* grab number of processes */
750 #if defined(__OpenBSD__)
752 mib[1] = KERN_NPROCS;
753 len = sizeof(nprocs);
754 sysctl(mib, 2, &nprocs, &len, NULL, 0);
760 e->command = "core show sysinfo";
762 "Usage: core show sysinfo\n"
763 " List current system information.\n";
769 ast_cli(a->fd, "\nSystem Statistics\n");
770 ast_cli(a->fd, "-----------------\n");
771 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
772 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
773 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
774 #if defined(HAVE_SYSINFO)
775 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
777 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
778 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
779 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
781 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
786 struct profile_entry {
788 uint64_t scale; /* if non-zero, values are scaled by this */
794 struct profile_data {
797 struct profile_entry e[0];
800 static struct profile_data *prof_data;
802 /*! \brief allocates a counter with a given name and scale.
803 * \return Returns the identifier of the counter.
805 int ast_add_profile(const char *name, uint64_t scale)
807 int l = sizeof(struct profile_data);
808 int n = 10; /* default entries */
810 if (prof_data == NULL) {
811 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
812 if (prof_data == NULL)
814 prof_data->entries = 0;
815 prof_data->max_size = n;
817 if (prof_data->entries >= prof_data->max_size) {
819 n = prof_data->max_size + 20;
820 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
824 prof_data->max_size = n;
826 n = prof_data->entries++;
827 prof_data->e[n].name = ast_strdup(name);
828 prof_data->e[n].value = 0;
829 prof_data->e[n].events = 0;
830 prof_data->e[n].mark = 0;
831 prof_data->e[n].scale = scale;
835 int64_t ast_profile(int i, int64_t delta)
837 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
839 if (prof_data->e[i].scale > 1)
840 delta /= prof_data->e[i].scale;
841 prof_data->e[i].value += delta;
842 prof_data->e[i].events++;
843 return prof_data->e[i].value;
846 /* The RDTSC instruction was introduced on the Pentium processor and is not
847 * implemented on certain clones, like the Cyrix 586. Hence, the previous
848 * expectation of __i386__ was in error. */
849 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
850 #if defined(__FreeBSD__)
851 #include <machine/cpufunc.h>
853 static __inline uint64_t
858 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
862 #else /* supply a dummy function on other platforms */
863 static __inline uint64_t
870 int64_t ast_mark(int i, int startstop)
872 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
875 prof_data->e[i].mark = rdtsc();
877 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
878 if (prof_data->e[i].scale > 1)
879 prof_data->e[i].mark /= prof_data->e[i].scale;
880 prof_data->e[i].value += prof_data->e[i].mark;
881 prof_data->e[i].events++;
883 return prof_data->e[i].mark;
886 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
887 max = prof_data->entries;\
888 if (a->argc > 3) { /* specific entries */ \
889 if (isdigit(a->argv[3][0])) { \
890 min = atoi(a->argv[3]); \
891 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
892 max = atoi(a->argv[4]); \
894 search = a->argv[3]; \
896 if (max > prof_data->entries) \
897 max = prof_data->entries;
899 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
902 const char *search = NULL;
905 e->command = "core show profile";
906 e->usage = "Usage: core show profile\n"
907 " show profile information";
913 if (prof_data == NULL)
916 DEFINE_PROFILE_MIN_MAX_VALUES;
917 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
918 prof_data->entries, prof_data->max_size);
919 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
920 "Value", "Average", "Name");
921 for (i = min; i < max; i++) {
922 struct profile_entry *entry = &prof_data->e[i];
923 if (!search || strstr(entry->name, search))
924 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
927 (long)entry->events, (long long)entry->value,
928 (long long)(entry->events ? entry->value / entry->events : entry->value),
934 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
937 const char *search = NULL;
940 e->command = "core clear profile";
941 e->usage = "Usage: core clear profile\n"
942 " clear profile information";
948 if (prof_data == NULL)
951 DEFINE_PROFILE_MIN_MAX_VALUES;
952 for (i= min; i < max; i++) {
953 if (!search || strstr(prof_data->e[i].name, search)) {
954 prof_data->e[i].value = 0;
955 prof_data->e[i].events = 0;
960 #undef DEFINE_PROFILE_MIN_MAX_VALUES
962 /*! \brief CLI command to list module versions */
963 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
965 #define FORMAT "%-25.25s %-40.40s\n"
966 struct file_version *iterator;
972 int matchlen, which = 0;
973 struct file_version *find;
977 e->command = "core show file version [like]";
979 "Usage: core show file version [like <pattern>]\n"
980 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
981 " Optional regular expression pattern is used to filter the file list.\n";
984 matchlen = strlen(a->word);
987 AST_RWLIST_RDLOCK(&file_versions);
988 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
989 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
990 ret = ast_strdup(find->file);
994 AST_RWLIST_UNLOCK(&file_versions);
1001 if (!strcasecmp(a->argv[4], "like")) {
1002 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
1003 return CLI_SHOWUSAGE;
1006 return CLI_SHOWUSAGE;
1014 return CLI_SHOWUSAGE;
1017 ast_cli(a->fd, FORMAT, "File", "Revision");
1018 ast_cli(a->fd, FORMAT, "----", "--------");
1019 AST_RWLIST_RDLOCK(&file_versions);
1020 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
1021 if (havename && strcasecmp(iterator->file, a->argv[4]))
1024 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
1027 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
1032 AST_RWLIST_UNLOCK(&file_versions);
1034 ast_cli(a->fd, "%d files listed.\n", count_files);
1044 #endif /* ! LOW_MEMORY */
1046 int ast_register_atexit(void (*func)(void))
1048 struct ast_atexit *ae;
1050 if (!(ae = ast_calloc(1, sizeof(*ae))))
1055 ast_unregister_atexit(func);
1057 AST_RWLIST_WRLOCK(&atexits);
1058 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
1059 AST_RWLIST_UNLOCK(&atexits);
1064 void ast_unregister_atexit(void (*func)(void))
1066 struct ast_atexit *ae = NULL;
1068 AST_RWLIST_WRLOCK(&atexits);
1069 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1070 if (ae->func == func) {
1071 AST_RWLIST_REMOVE_CURRENT(list);
1075 AST_RWLIST_TRAVERSE_SAFE_END;
1076 AST_RWLIST_UNLOCK(&atexits);
1081 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1082 static int fdsend(int fd, const char *s)
1084 return write(fd, s, strlen(s) + 1);
1087 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1088 static int fdprint(int fd, const char *s)
1090 return write(fd, s, strlen(s));
1093 /*! \brief NULL handler so we can collect the child exit status */
1094 static void _null_sig_handler(int sig)
1098 static struct sigaction null_sig_handler = {
1099 .sa_handler = _null_sig_handler,
1100 .sa_flags = SA_RESTART,
1103 static struct sigaction ignore_sig_handler = {
1104 .sa_handler = SIG_IGN,
1107 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1108 /*! \brief Keep track of how many threads are currently trying to wait*() on
1111 static unsigned int safe_system_level = 0;
1112 static struct sigaction safe_system_prev_handler;
1114 void ast_replace_sigchld(void)
1118 ast_mutex_lock(&safe_system_lock);
1119 level = safe_system_level++;
1121 /* only replace the handler if it has not already been done */
1123 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1126 ast_mutex_unlock(&safe_system_lock);
1129 void ast_unreplace_sigchld(void)
1133 ast_mutex_lock(&safe_system_lock);
1134 level = --safe_system_level;
1136 /* only restore the handler if we are the last one */
1138 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1141 ast_mutex_unlock(&safe_system_lock);
1144 int ast_safe_system(const char *s)
1148 struct rusage rusage;
1151 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1152 ast_replace_sigchld();
1154 #ifdef HAVE_WORKING_FORK
1162 cap_t cap = cap_from_text("cap_net_admin-eip");
1164 if (cap_set_proc(cap)) {
1165 /* Careful with order! Logging cannot happen after we close FDs */
1166 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1170 #ifdef HAVE_WORKING_FORK
1171 if (ast_opt_high_priority)
1172 ast_set_priority(0);
1173 /* Close file descriptors and launch system command */
1174 ast_close_fds_above_n(STDERR_FILENO);
1176 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1178 } else if (pid > 0) {
1180 res = wait4(pid, &status, 0, &rusage);
1182 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1184 } else if (errno != EINTR)
1188 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1192 ast_unreplace_sigchld();
1193 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1201 * \brief enable or disable a logging level to a specified console
1203 void ast_console_toggle_loglevel(int fd, int level, int state)
1207 if (level >= NUMLOGLEVELS) {
1208 level = NUMLOGLEVELS - 1;
1211 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1212 if (fd == consoles[x].fd) {
1214 * Since the logging occurs when levels are false, set to
1215 * flipped iinput because this function accepts 0 as off and 1 as on
1217 consoles[x].levels[level] = state ? 0 : 1;
1224 * \brief mute or unmute a console from logging
1226 void ast_console_toggle_mute(int fd, int silent)
1229 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1230 if (fd == consoles[x].fd) {
1231 if (consoles[x].mute) {
1232 consoles[x].mute = 0;
1234 ast_cli(fd, "Console is not muted anymore.\n");
1236 consoles[x].mute = 1;
1238 ast_cli(fd, "Console is muted.\n");
1243 ast_cli(fd, "Couldn't find remote console.\n");
1247 * \brief log the string to all attached console clients
1249 static void ast_network_puts_mutable(const char *string, int level)
1252 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1253 if (consoles[x].mute)
1255 if (consoles[x].fd > -1) {
1256 if (!consoles[x].levels[level])
1257 fdprint(consoles[x].p[1], string);
1263 * \brief log the string to the console, and all attached
1266 void ast_console_puts_mutable(const char *string, int level)
1268 fputs(string, stdout);
1270 ast_network_puts_mutable(string, level);
1274 * \brief write the string to all attached console clients
1276 static void ast_network_puts(const char *string)
1279 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1280 if (consoles[x].fd > -1)
1281 fdprint(consoles[x].p[1], string);
1286 * \brief write the string to the console, and all attached
1289 void ast_console_puts(const char *string)
1291 fputs(string, stdout);
1293 ast_network_puts(string);
1296 static void network_verboser(const char *s)
1298 ast_network_puts_mutable(s, __LOG_VERBOSE);
1301 static pthread_t lthread;
1304 * \brief read() function supporting the reception of user credentials.
1306 * \param fd Socket file descriptor.
1307 * \param buffer Receive buffer.
1308 * \param size 'buffer' size.
1309 * \param con Console structure to set received credentials
1310 * \retval -1 on error
1311 * \retval the number of bytes received on success.
1313 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1315 #if defined(SO_PEERCRED)
1316 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1317 #define HAVE_STRUCT_UCRED_UID
1318 struct sockpeercred cred;
1322 socklen_t len = sizeof(cred);
1324 #if defined(HAVE_GETPEEREID)
1332 result = read(fd, buffer, size);
1337 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1338 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1341 #if defined(HAVE_STRUCT_UCRED_UID)
1344 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1347 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1349 #elif defined(HAVE_GETPEEREID)
1350 if (getpeereid(fd, &uid, &gid)) {
1362 static void *netconsole(void *vconsole)
1364 struct console *con = vconsole;
1365 char hostname[MAXHOSTNAMELEN] = "";
1368 const char * const end_buf = inbuf + sizeof(inbuf);
1369 char *start_read = inbuf;
1371 struct pollfd fds[2];
1373 if (gethostname(hostname, sizeof(hostname)-1))
1374 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1375 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1376 fdprint(con->fd, outbuf);
1378 fds[0].fd = con->fd;
1379 fds[0].events = POLLIN;
1381 fds[1].fd = con->p[0];
1382 fds[1].events = POLLIN;
1385 res = ast_poll(fds, 2, -1);
1388 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1391 if (fds[0].revents) {
1392 int cmds_read, bytes_read;
1393 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1396 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1397 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1398 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1401 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1402 * NULL and not trailing partial commands. */
1403 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1404 /* No commands were read. We either have a short read on the first command
1405 * with space left, or a command that is too long */
1406 if (start_read + bytes_read < end_buf) {
1407 start_read += bytes_read;
1409 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1414 if (start_read[bytes_read - 1] == '\0') {
1415 /* The read ended on a command boundary, start reading again at the head of inbuf */
1419 /* If we get this far, we have left over characters that have not been processed.
1420 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1421 * We are guaranteed to have at least cmds_read NULLs */
1422 while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1425 memmove(inbuf, start_read, end_buf - start_read);
1426 start_read = end_buf - start_read + inbuf;
1428 if (fds[1].revents) {
1429 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1431 ast_log(LOG_ERROR, "read returned %d\n", res);
1434 res = write(con->fd, outbuf, res);
1439 if (!ast_opt_hide_connect) {
1440 ast_verb(3, "Remote UNIX connection disconnected\n");
1450 static void *listener(void *unused)
1452 struct sockaddr_un sunaddr;
1457 struct pollfd fds[1];
1461 fds[0].fd = ast_socket;
1462 fds[0].events = POLLIN;
1463 s = ast_poll(fds, 1, -1);
1464 pthread_testcancel();
1467 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1470 len = sizeof(sunaddr);
1471 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1474 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1476 #if !defined(SO_PASSCRED)
1480 /* turn on socket credentials passing. */
1481 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1482 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1485 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1486 if (consoles[x].fd >= 0) {
1489 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1490 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1491 consoles[x].fd = -1;
1492 fdprint(s, "Server failed to create pipe\n");
1496 flags = fcntl(consoles[x].p[1], F_GETFL);
1497 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1499 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1500 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1501 to know if the user didn't send the credentials. */
1502 consoles[x].uid = -2;
1503 consoles[x].gid = -2;
1504 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1505 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1506 close(consoles[x].p[0]);
1507 close(consoles[x].p[1]);
1508 consoles[x].fd = -1;
1509 fdprint(s, "Server failed to spawn thread\n");
1514 if (x >= AST_MAX_CONNECTS) {
1515 fdprint(s, "No more connections allowed\n");
1516 ast_log(LOG_WARNING, "No more connections allowed\n");
1518 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1519 ast_verb(3, "Remote UNIX connection\n");
1527 static int ast_makesocket(void)
1529 struct sockaddr_un sunaddr;
1535 for (x = 0; x < AST_MAX_CONNECTS; x++)
1536 consoles[x].fd = -1;
1537 unlink(ast_config_AST_SOCKET);
1538 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1539 if (ast_socket < 0) {
1540 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1543 memset(&sunaddr, 0, sizeof(sunaddr));
1544 sunaddr.sun_family = AF_LOCAL;
1545 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1546 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1548 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1553 res = listen(ast_socket, 2);
1555 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1560 if (ast_register_verbose(network_verboser)) {
1561 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1564 if (ast_pthread_create_background(<hread, NULL, listener, NULL)) {
1565 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1570 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1572 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1573 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1578 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1580 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1581 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1586 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1587 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1589 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1592 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1594 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1595 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1601 static int ast_tryconnect(void)
1603 struct sockaddr_un sunaddr;
1605 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1606 if (ast_consock < 0) {
1607 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1610 memset(&sunaddr, 0, sizeof(sunaddr));
1611 sunaddr.sun_family = AF_LOCAL;
1612 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1613 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1622 /*! \brief Urgent handler
1624 * Called by soft_hangup to interrupt the poll, read, or other
1625 * system call. We don't actually need to do anything though.
1626 * Remember: Cannot EVER ast_log from within a signal handler
1628 static void _urg_handler(int num)
1633 static struct sigaction urg_handler = {
1634 .sa_handler = _urg_handler,
1635 .sa_flags = SA_RESTART,
1638 static void _hup_handler(int num)
1640 int a = 0, save_errno = errno;
1641 printf("Received HUP signal -- Reloading configs\n");
1643 execvp(_argv[0], _argv);
1644 sig_flags.need_reload = 1;
1645 if (sig_alert_pipe[1] != -1) {
1646 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1647 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1653 static struct sigaction hup_handler = {
1654 .sa_handler = _hup_handler,
1655 .sa_flags = SA_RESTART,
1658 static void _child_handler(int sig)
1660 /* Must not ever ast_log or ast_verbose within signal handler */
1661 int n, status, save_errno = errno;
1664 * Reap all dead children -- not just one
1666 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1668 if (n == 0 && option_debug)
1669 printf("Huh? Child handler, but nobody there?\n");
1673 static struct sigaction child_handler = {
1674 .sa_handler = _child_handler,
1675 .sa_flags = SA_RESTART,
1678 /*! \brief Set maximum open files */
1679 static void set_ulimit(int value)
1681 struct rlimit l = {0, 0};
1684 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1691 if (setrlimit(RLIMIT_NOFILE, &l)) {
1692 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1696 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1701 /*! \brief Set an X-term or screen title */
1702 static void set_title(char *text)
1704 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1705 fprintf(stdout, "\033]2;%s\007", text);
1708 static void set_icon(char *text)
1710 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1711 fprintf(stdout, "\033]1;%s\007", text);
1714 /*! \brief We set ourselves to a high priority, that we might pre-empt
1715 * everything else. If your PBX has heavy activity on it, this is a
1718 int ast_set_priority(int pri)
1720 struct sched_param sched;
1721 memset(&sched, 0, sizeof(sched));
1724 sched.sched_priority = 10;
1725 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1726 ast_log(LOG_WARNING, "Unable to set high priority\n");
1729 ast_verb(1, "Set to realtime thread\n");
1731 sched.sched_priority = 0;
1732 /* According to the manpage, these parameters can never fail. */
1733 sched_setscheduler(0, SCHED_OTHER, &sched);
1737 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1738 ast_log(LOG_WARNING, "Unable to set high priority\n");
1741 ast_verb(1, "Set to high priority\n");
1743 /* According to the manpage, these parameters can never fail. */
1744 setpriority(PRIO_PROCESS, 0, 0);
1750 static void ast_run_atexits(void)
1752 struct ast_atexit *ae;
1753 AST_RWLIST_RDLOCK(&atexits);
1754 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1758 AST_RWLIST_UNLOCK(&atexits);
1761 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1762 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1764 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1766 if (can_safely_quit(niceness, restart)) {
1767 really_quit(num, niceness, restart);
1768 /* No one gets here. */
1770 /* It wasn't our time. */
1773 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1775 /* Check if someone else isn't already doing this. */
1776 ast_mutex_lock(&safe_system_lock);
1777 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1778 /* Already in progress and other request was less nice. */
1779 ast_mutex_unlock(&safe_system_lock);
1780 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1783 shuttingdown = niceness;
1784 ast_mutex_unlock(&safe_system_lock);
1786 /* Try to get as many CDRs as possible submitted to the backend engines
1787 * (if in batch mode). really_quit happens to call it again when running
1788 * the atexit handlers, otherwise this would be a bit early. */
1789 ast_cdr_engine_term();
1792 if (niceness == SHUTDOWN_NORMAL) {
1794 /* Begin shutdown routine, hanging up active channels */
1795 ast_begin_shutdown(1);
1796 if (option_verbose && ast_opt_console) {
1797 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1802 /* Wait up to 15 seconds for all channels to go away */
1803 if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1806 /* Sleep 1/10 of a second */
1809 } else if (niceness >= SHUTDOWN_NICE) {
1810 if (niceness != SHUTDOWN_REALLY_NICE) {
1811 ast_begin_shutdown(0);
1813 if (option_verbose && ast_opt_console) {
1814 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1817 if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1824 /* Re-acquire lock and check if someone changed the niceness, in which
1825 * case someone else has taken over the shutdown.
1827 ast_mutex_lock(&safe_system_lock);
1828 if (shuttingdown != niceness) {
1829 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1830 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1832 ast_mutex_unlock(&safe_system_lock);
1835 shuttingdown = SHUTTING_DOWN;
1836 ast_mutex_unlock(&safe_system_lock);
1841 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1843 if (niceness >= SHUTDOWN_NICE) {
1844 ast_module_shutdown();
1847 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1848 char filename[80] = "";
1849 if (getenv("HOME")) {
1850 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1852 if (!ast_strlen_zero(filename)) {
1853 ast_el_write_history(filename);
1855 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1856 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1860 if (el_hist != NULL) {
1861 history_end(el_hist);
1863 } else if (mon_sig_flags == pthread_self()) {
1864 if (consolethread != AST_PTHREADT_NULL) {
1865 pthread_kill(consolethread, SIGURG);
1869 ast_verb(0, "Executing last minute cleanups\n");
1871 /* Called on exit */
1872 ast_verb(0, "Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1873 ast_debug(1, "Asterisk ending (%d).\n", num);
1875 <managerEventInstance>
1876 <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
1878 <parameter name="Shutdown">
1880 <enum name="Uncleanly"/>
1881 <enum name="Cleanly"/>
1884 <parameter name="Restart">
1887 <enum name="False"/>
1891 </managerEventInstance>
1893 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1894 if (ast_socket > -1) {
1895 pthread_cancel(lthread);
1898 unlink(ast_config_AST_SOCKET);
1900 if (ast_consock > -1)
1902 if (!ast_opt_remote)
1903 unlink(ast_config_AST_PID);
1904 printf("%s", term_quit());
1907 ast_verb(0, "Preparing for Asterisk restart...\n");
1908 /* Mark all FD's for closing on exec */
1909 for (i = 3; i < 32768; i++) {
1910 fcntl(i, F_SETFD, FD_CLOEXEC);
1912 ast_verb(0, "Asterisk is now restarting...\n");
1918 /* If there is a consolethread running send it a SIGHUP
1919 so it can execvp, otherwise we can do it ourselves */
1920 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1921 pthread_kill(consolethread, SIGHUP);
1922 /* Give the signal handler some time to complete */
1925 execvp(_argv[0], _argv);
1935 static void __quit_handler(int num)
1938 sig_flags.need_quit = 1;
1939 if (sig_alert_pipe[1] != -1) {
1940 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1941 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1944 /* There is no need to restore the signal handler here, since the app
1945 * is going to exit */
1948 static void __remote_quit_handler(int num)
1950 sig_flags.need_quit = 1;
1953 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1957 if (!strncmp(s, cmp, strlen(cmp))) {
1958 c = s + strlen(cmp);
1959 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1965 /* These gymnastics are due to platforms which designate char as unsigned by
1966 * default. Level is the negative character -- offset by 1, because \0 is the
1968 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
1969 #define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
1971 static void console_verboser(const char *s)
1974 const char *c = NULL;
1977 if (VERBOSE_HASMAGIC(s)) {
1978 level = VERBOSE_MAGIC2LEVEL(s);
1980 if (level > option_verbose) {
1985 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1986 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1987 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1988 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1997 /* Wake up a poll()ing console */
1998 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
1999 pthread_kill(consolethread, SIGURG);
2003 static int ast_all_zeros(char *s)
2013 static void consolehandler(char *s)
2015 printf("%s", term_end());
2018 /* Called when readline data is available */
2019 if (!ast_all_zeros(s))
2020 ast_el_add_history(s);
2021 /* The real handler for bang */
2024 ast_safe_system(s+1);
2026 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2028 ast_cli_command(STDOUT_FILENO, s);
2031 static int remoteconsolehandler(char *s)
2035 /* Called when readline data is available */
2036 if (!ast_all_zeros(s))
2037 ast_el_add_history(s);
2038 /* The real handler for bang */
2041 ast_safe_system(s+1);
2043 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2045 } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2046 int old_verbose = option_verbose;
2047 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2049 if (sscanf(s + 25, "%d", &tmp) != 1) {
2050 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2052 if (tmp > option_verbose) {
2053 option_verbose = tmp;
2055 if (old_verbose != option_verbose) {
2056 fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2058 fprintf(stdout, "Verbosity level unchanged.\n");
2062 if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2063 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2065 if (old_verbose != option_verbose) {
2066 fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2068 fprintf(stdout, "Verbosity level unchanged.\n");
2073 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2074 (s[4] == '\0' || isspace(s[4]))) {
2075 quit_handler(0, SHUTDOWN_FAST, 0);
2082 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2086 e->command = "core show version";
2088 "Usage: core show version\n"
2089 " Shows Asterisk version information.\n";
2096 return CLI_SHOWUSAGE;
2097 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2098 ast_get_version(), ast_build_user, ast_build_hostname,
2099 ast_build_machine, ast_build_os, ast_build_date);
2104 static int handle_quit(int fd, int argc, char *argv[])
2107 return RESULT_SHOWUSAGE;
2108 quit_handler(0, SHUTDOWN_NORMAL, 0);
2109 return RESULT_SUCCESS;
2113 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2117 e->command = "core stop now";
2119 "Usage: core stop now\n"
2120 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2126 if (a->argc != e->args)
2127 return CLI_SHOWUSAGE;
2128 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2132 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2136 e->command = "core stop gracefully";
2138 "Usage: core stop gracefully\n"
2139 " Causes Asterisk to not accept new calls, and exit when all\n"
2140 " active calls have terminated normally.\n";
2146 if (a->argc != e->args)
2147 return CLI_SHOWUSAGE;
2148 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2152 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2156 e->command = "core stop when convenient";
2158 "Usage: core stop when convenient\n"
2159 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2165 if (a->argc != e->args)
2166 return CLI_SHOWUSAGE;
2167 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2168 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2172 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2176 e->command = "core restart now";
2178 "Usage: core restart now\n"
2179 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2186 if (a->argc != e->args)
2187 return CLI_SHOWUSAGE;
2188 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2192 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2196 e->command = "core restart gracefully";
2198 "Usage: core restart gracefully\n"
2199 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2200 " restart when all active calls have ended.\n";
2206 if (a->argc != e->args)
2207 return CLI_SHOWUSAGE;
2208 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2212 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2216 e->command = "core restart when convenient";
2218 "Usage: core restart when convenient\n"
2219 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2225 if (a->argc != e->args)
2226 return CLI_SHOWUSAGE;
2227 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2228 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2232 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2234 int aborting_shutdown = 0;
2238 e->command = "core abort shutdown";
2240 "Usage: core abort shutdown\n"
2241 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2242 " call operations.\n";
2248 if (a->argc != e->args)
2249 return CLI_SHOWUSAGE;
2251 ast_mutex_lock(&safe_system_lock);
2252 if (shuttingdown >= SHUTDOWN_FAST) {
2253 aborting_shutdown = 1;
2254 shuttingdown = NOT_SHUTTING_DOWN;
2256 ast_mutex_unlock(&safe_system_lock);
2258 if (aborting_shutdown) {
2259 ast_cancel_shutdown();
2264 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2270 "Usage: !<command>\n"
2271 " Executes a given shell command\n";
2279 static const char warranty_lines[] = {
2283 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2284 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2285 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2286 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2287 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2288 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2289 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2290 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2291 "REPAIR OR CORRECTION.\n"
2293 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2294 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2295 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2296 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2297 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2298 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2299 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2300 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2301 "POSSIBILITY OF SUCH DAMAGES.\n"
2304 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2308 e->command = "core show warranty";
2310 "Usage: core show warranty\n"
2311 " Shows the warranty (if any) for this copy of Asterisk.\n";
2317 ast_cli(a->fd, "%s", warranty_lines);
2322 static const char license_lines[] = {
2324 "This program is free software; you can redistribute it and/or modify\n"
2325 "it under the terms of the GNU General Public License version 2 as\n"
2326 "published by the Free Software Foundation.\n"
2328 "This program also contains components licensed under other licenses.\n"
2331 "This program is distributed in the hope that it will be useful,\n"
2332 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2333 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2334 "GNU General Public License for more details.\n"
2336 "You should have received a copy of the GNU General Public License\n"
2337 "along with this program; if not, write to the Free Software\n"
2338 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2341 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2345 e->command = "core show license";
2347 "Usage: core show license\n"
2348 " Shows the license(s) for this copy of Asterisk.\n";
2354 ast_cli(a->fd, "%s", license_lines);
2359 #define ASTERISK_PROMPT "*CLI> "
2361 #define ASTERISK_PROMPT2 "%s*CLI> "
2363 static struct ast_cli_entry cli_asterisk[] = {
2364 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2365 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2366 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2367 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2368 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2369 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2370 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2371 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2372 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2373 AST_CLI_DEFINE(handle_version, "Display version info"),
2374 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2375 #if !defined(LOW_MEMORY)
2376 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2377 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2378 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2379 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2381 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2382 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2383 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2384 #endif /* ! LOW_MEMORY */
2387 struct el_read_char_state_struct {
2388 unsigned int line_full:1;
2389 unsigned int prev_line_full:1;
2390 char prev_line_verbosity;
2393 static int el_read_char_state_init(void *ptr)
2395 struct el_read_char_state_struct *state = ptr;
2396 state->line_full = 1;
2397 state->prev_line_full = 1;
2398 state->prev_line_verbosity = 0;
2402 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2404 static int ast_el_read_char(EditLine *editline, char *cp)
2408 struct pollfd fds[2];
2411 #define EL_BUF_SIZE 512
2412 char buf[EL_BUF_SIZE];
2413 struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2417 fds[0].fd = ast_consock;
2418 fds[0].events = POLLIN;
2419 if (!ast_opt_exec) {
2420 fds[1].fd = STDIN_FILENO;
2421 fds[1].events = POLLIN;
2424 res = ast_poll(fds, max, -1);
2426 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2430 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2434 if (!ast_opt_exec && fds[1].revents) {
2435 num_read = read(STDIN_FILENO, cp, 1);
2442 if (fds[0].revents) {
2444 char *curline = buf, *nextline;
2445 res = read(ast_consock, buf, sizeof(buf) - 1);
2446 /* if the remote side disappears exit */
2448 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2449 if (!ast_opt_reconnect) {
2450 quit_handler(0, SHUTDOWN_FAST, 0);
2453 int reconnects_per_second = 20;
2454 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2455 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2456 if (ast_tryconnect()) {
2457 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2458 printf("%s", term_quit());
2461 fdsend(ast_consock, "logger mute silent");
2463 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2466 usleep(1000000 / reconnects_per_second);
2468 if (tries >= 30 * reconnects_per_second) {
2469 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2470 quit_handler(0, SHUTDOWN_FAST, 0);
2478 /* Write over the CLI prompt */
2479 if (!ast_opt_exec && !lastpos) {
2480 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2485 state->prev_line_full = state->line_full;
2486 if ((nextline = strchr(curline, '\n'))) {
2487 state->line_full = 1;
2490 state->line_full = 0;
2491 nextline = strchr(curline, '\0');
2494 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2495 level = VERBOSE_MAGIC2LEVEL(curline);
2497 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2498 /* Non-verbose output */
2501 level = state->prev_line_verbosity;
2503 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2504 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2508 state->prev_line_verbosity = level;
2510 } while (!ast_strlen_zero(curline));
2512 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2524 static struct ast_str *prompt = NULL;
2526 static char *cli_prompt(EditLine *editline)
2531 static int cli_prompt_changes = 0;
2536 if (prompt == NULL) {
2537 prompt = ast_str_create(100);
2538 } else if (!cli_prompt_changes) {
2539 return ast_str_buffer(prompt);
2541 ast_str_reset(prompt);
2544 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2546 struct timeval ts = ast_tvnow();
2547 while (*t != '\0') {
2549 char hostname[MAXHOSTNAMELEN] = "";
2551 struct ast_tm tm = { 0, };
2552 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2556 case 'C': /* color */
2558 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2559 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2561 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2562 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2566 /* If the color has been reset correctly, then there's no need to reset it later */
2567 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2569 case 'd': /* date */
2570 if (ast_localtime(&ts, &tm, NULL)) {
2571 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2572 ast_str_append(&prompt, 0, "%s", tmp);
2573 cli_prompt_changes++;
2576 case 'g': /* group */
2577 if ((gr = getgrgid(getgid()))) {
2578 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2581 case 'h': /* hostname */
2582 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2583 ast_str_append(&prompt, 0, "%s", hostname);
2585 ast_str_append(&prompt, 0, "%s", "localhost");
2588 case 'H': /* short hostname */
2589 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2591 if ((dotptr = strchr(hostname, '.'))) {
2594 ast_str_append(&prompt, 0, "%s", hostname);
2596 ast_str_append(&prompt, 0, "%s", "localhost");
2599 #ifdef HAVE_GETLOADAVG
2600 case 'l': /* load avg */
2602 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2604 getloadavg(list, 3);
2605 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2606 cli_prompt_changes++;
2610 case 's': /* Asterisk system name (from asterisk.conf) */
2611 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2613 case 't': /* time */
2614 if (ast_localtime(&ts, &tm, NULL)) {
2615 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2616 ast_str_append(&prompt, 0, "%s", tmp);
2617 cli_prompt_changes++;
2620 case 'u': /* username */
2621 if ((pw = getpwuid(getuid()))) {
2622 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2625 case '#': /* process console or remote? */
2626 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2628 case '%': /* literal % */
2629 ast_str_append(&prompt, 0, "%c", '%');
2631 case '\0': /* % is last character - prevent bug */
2636 ast_str_append(&prompt, 0, "%c", *t);
2641 /* Force colors back to normal at end */
2642 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2644 } else if (remotehostname) {
2645 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2647 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2650 return ast_str_buffer(prompt);
2653 static char **ast_el_strtoarr(char *buf)
2655 char **match_list = NULL, **match_list_tmp, *retstr;
2656 size_t match_list_len;
2660 while ( (retstr = strsep(&buf, " ")) != NULL) {
2662 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2664 if (matches + 1 >= match_list_len) {
2665 match_list_len <<= 1;
2666 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2667 match_list = match_list_tmp;
2670 ast_free(match_list);
2671 return (char **) NULL;
2675 match_list[matches++] = ast_strdup(retstr);
2679 return (char **) NULL;
2681 if (matches >= match_list_len) {
2682 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2683 match_list = match_list_tmp;
2686 ast_free(match_list);
2687 return (char **) NULL;
2691 match_list[matches] = (char *) NULL;
2696 static int ast_el_sort_compare(const void *i1, const void *i2)
2700 s1 = ((char **)i1)[0];
2701 s2 = ((char **)i2)[0];
2703 return strcasecmp(s1, s2);
2706 static int ast_cli_display_match_list(char **matches, int len, int max)
2708 int i, idx, limit, count;
2709 int screenwidth = 0;
2710 int numoutput = 0, numoutputline = 0;
2712 screenwidth = ast_get_termcols(STDOUT_FILENO);
2714 /* find out how many entries can be put on one line, with two spaces between strings */
2715 limit = screenwidth / (max + 2);
2719 /* how many lines of output */
2720 count = len / limit;
2721 if (count * limit < len)
2726 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2728 for (; count > 0; count--) {
2730 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2732 /* Don't print dupes */
2733 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2735 ast_free(matches[idx]);
2736 matches[idx] = NULL;
2742 fprintf(stdout, "%-*s ", max, matches[idx]);
2743 ast_free(matches[idx]);
2744 matches[idx] = NULL;
2746 if (numoutputline > 0)
2747 fprintf(stdout, "\n");
2754 static char *cli_complete(EditLine *editline, int ch)
2760 int retval = CC_ERROR;
2761 char buf[2048], savechr;
2764 LineInfo *lf = (LineInfo *)el_line(editline);
2766 savechr = *(char *)lf->cursor;
2767 *(char *)lf->cursor = '\0';
2768 ptr = (char *)lf->cursor;
2770 while (ptr > lf->buffer) {
2771 if (isspace(*ptr)) {
2779 len = lf->cursor - ptr;
2781 if (ast_opt_remote) {
2782 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2783 fdsend(ast_consock, buf);
2784 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2785 return (char*)(CC_ERROR);
2788 nummatches = atoi(buf);
2790 if (nummatches > 0) {
2792 int mlen = 0, maxmbuf = 2048;
2793 /* Start with a 2048 byte buffer */
2794 if (!(mbuf = ast_malloc(maxmbuf))) {
2795 *((char *) lf->cursor) = savechr;
2796 return (char *)(CC_ERROR);
2798 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2799 fdsend(ast_consock, buf);
2802 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2803 if (mlen + 1024 > maxmbuf) {
2804 /* Every step increment buffer 1024 bytes */
2806 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2807 *((char *) lf->cursor) = savechr;
2808 return (char *)(CC_ERROR);
2811 /* Only read 1024 bytes at a time */
2812 res = read(ast_consock, mbuf + mlen, 1024);
2818 matches = ast_el_strtoarr(mbuf);
2821 matches = (char **) NULL;
2823 char **p, *oldbuf=NULL;
2825 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2826 for (p = matches; p && *p; p++) {
2827 if (!oldbuf || strcmp(*p,oldbuf))
2835 int matches_num, maxlen, match_len;
2837 if (matches[0][0] != '\0') {
2838 el_deletestr(editline, (int) len);
2839 el_insertstr(editline, matches[0]);
2840 retval = CC_REFRESH;
2843 if (nummatches == 1) {
2844 /* Found an exact match */
2845 el_insertstr(editline, " ");
2846 retval = CC_REFRESH;
2848 /* Must be more than one match */
2849 for (i = 1, maxlen = 0; matches[i]; i++) {
2850 match_len = strlen(matches[i]);
2851 if (match_len > maxlen)
2854 matches_num = i - 1;
2855 if (matches_num >1) {
2856 fprintf(stdout, "\n");
2857 ast_cli_display_match_list(matches, nummatches, maxlen);
2858 retval = CC_REDISPLAY;
2860 el_insertstr(editline," ");
2861 retval = CC_REFRESH;
2864 for (i = 0; matches[i]; i++)
2865 ast_free(matches[i]);
2869 *((char *) lf->cursor) = savechr;
2871 return (char *)(long)retval;
2874 static int ast_el_initialize(void)
2877 char *editor, *editrc = getenv("EDITRC");
2879 if (!(editor = getenv("AST_EDITMODE"))) {
2880 if (!(editor = getenv("AST_EDITOR"))) {
2887 if (el_hist != NULL)
2888 history_end(el_hist);
2890 el = el_init("asterisk", stdin, stdout, stderr);
2891 el_set(el, EL_PROMPT, cli_prompt);
2893 el_set(el, EL_EDITMODE, 1);
2894 el_set(el, EL_EDITOR, editor);
2895 el_hist = history_init();
2896 if (!el || !el_hist)
2899 /* setup history with 100 entries */
2900 history(el_hist, &ev, H_SETSIZE, 100);
2902 el_set(el, EL_HIST, history, el_hist);
2904 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2905 /* Bind <tab> to command completion */
2906 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2907 /* Bind ? to command completion */
2908 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2909 /* Bind ^D to redisplay */
2910 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2911 /* Bind Delete to delete char left */
2912 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
2913 /* Bind Home and End to move to line start and end */
2914 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
2915 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
2916 /* Bind C-left and C-right to move by word (not all terminals) */
2917 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
2918 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
2921 el_source(el, editrc);
2927 #define MAX_HISTORY_COMMAND_LENGTH 256
2929 static int ast_el_add_history(char *buf)
2933 if (el_hist == NULL || el == NULL)
2934 ast_el_initialize();
2935 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2937 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2940 static int ast_el_write_history(char *filename)
2944 if (el_hist == NULL || el == NULL)
2945 ast_el_initialize();
2947 return (history(el_hist, &ev, H_SAVE, filename));
2950 static int ast_el_read_history(char *filename)
2954 if (el_hist == NULL || el == NULL) {
2955 ast_el_initialize();
2958 return history(el_hist, &ev, H_LOAD, filename);
2961 static void ast_remotecontrol(char *data)
2965 char filename[80] = "";
2970 char *stringp = NULL;
2975 memset(&sig_flags, 0, sizeof(sig_flags));
2976 signal(SIGINT, __remote_quit_handler);
2977 signal(SIGTERM, __remote_quit_handler);
2978 signal(SIGHUP, __remote_quit_handler);
2980 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2981 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2985 char prefix[] = "cli quit after ";
2986 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
2987 sprintf(tmp, "%s%s", prefix, data);
2988 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2989 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2990 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
2996 hostname = strsep(&stringp, "/");
2997 cpid = strsep(&stringp, "/");
2998 version = strsep(&stringp, "\n");
3000 version = "<Version Unknown>";
3002 strsep(&stringp, ".");
3008 if (!ast_opt_mute) {
3009 fdsend(ast_consock, "logger mute silent");
3011 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3015 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
3016 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3018 fds.fd = ast_consock;
3019 fds.events = POLLIN;
3022 while (ast_poll(&fds, 1, 60000) > 0) {
3023 char buffer[512] = "", *curline = buffer, *nextline;
3024 int not_written = 1;
3026 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3030 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3035 prev_linefull = linefull;
3036 if ((nextline = strchr(curline, '\n'))) {
3041 nextline = strchr(curline, '\0');
3044 /* Skip verbose lines */
3045 /* Prev line full? | Line is verbose | Last line verbose? | Print
3046 * TRUE | TRUE* | TRUE | FALSE
3047 * TRUE | TRUE* | FALSE | FALSE
3048 * TRUE | FALSE* | TRUE | TRUE
3049 * TRUE | FALSE* | FALSE | TRUE
3050 * FALSE | TRUE | TRUE* | FALSE
3051 * FALSE | TRUE | FALSE* | TRUE
3052 * FALSE | FALSE | TRUE* | FALSE
3053 * FALSE | FALSE | FALSE* | TRUE
3055 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3056 prev_line_verbose = 0;
3058 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3059 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3062 prev_line_verbose = 1;
3065 } while (!ast_strlen_zero(curline));
3067 /* No non-verbose output in 60 seconds. */
3075 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3076 remotehostname = hostname;
3078 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3079 if (el_hist == NULL || el == NULL)
3080 ast_el_initialize();
3082 el_set(el, EL_GETCFN, ast_el_read_char);
3084 if (!ast_strlen_zero(filename))
3085 ast_el_read_history(filename);
3088 ebuf = (char *)el_gets(el, &num);
3090 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3094 if (!ebuf && write(1, "", 1) < 0)
3097 if (!ast_strlen_zero(ebuf)) {
3098 if (ebuf[strlen(ebuf)-1] == '\n')
3099 ebuf[strlen(ebuf)-1] = '\0';
3100 if (!remoteconsolehandler(ebuf)) {
3101 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3103 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3109 printf("\nDisconnected from Asterisk server\n");
3112 static int show_version(void)
3114 printf("Asterisk %s\n", ast_get_version());
3118 static int show_cli_help(void)
3120 printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3121 printf("Usage: asterisk [OPTIONS]\n");
3122 printf("Valid Options:\n");
3123 printf(" -V Display version number and exit\n");
3124 printf(" -C <configfile> Use an alternate configuration file\n");
3125 printf(" -G <group> Run as a group other than the caller\n");
3126 printf(" -U <user> Run as a user other than the caller\n");
3127 printf(" -c Provide console CLI\n");
3128 printf(" -d Enable extra debugging\n");
3129 #if HAVE_WORKING_FORK
3130 printf(" -f Do not fork\n");
3131 printf(" -F Always fork\n");
3133 printf(" -g Dump core in case of a crash\n");
3134 printf(" -h This help screen\n");
3135 printf(" -i Initialize crypto keys at startup\n");
3136 printf(" -I Enable internal timing if DAHDI timer is available\n");
3137 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
3138 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
3139 printf(" -m Mute debugging and console output on the console\n");
3140 printf(" -n Disable console colorization\n");
3141 printf(" -p Run as pseudo-realtime thread\n");
3142 printf(" -q Quiet mode (suppress output)\n");
3143 printf(" -r Connect to Asterisk on this machine\n");
3144 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
3145 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
3146 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
3147 printf(" belong after they are done\n");
3148 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3149 printf(" of output to the CLI\n");
3150 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
3151 printf(" -x <cmd> Execute command <cmd> (implies -r)\n");
3152 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
3153 printf(" -W Adjust terminal colors to compensate for a light background\n");
3158 static void ast_readconfig(void)
3160 struct ast_config *cfg;
3161 struct ast_variable *v;
3162 char *config = DEFAULT_CONFIG_FILE;
3163 char hostname[MAXHOSTNAMELEN] = "";
3164 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3166 unsigned int dbdir:1;
3167 unsigned int keydir:1;
3170 /* Set default value */