2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2012, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
22 * \mainpage Asterisk -- The Open Source Telephony Project
26 * This documentation created by the Doxygen project clearly explains the
27 * internals of the Asterisk software. This documentation contains basic
28 * examples, developer documentation, support information, and information
31 * \section community Community
32 * Asterisk is a big project and has a busy community. Look at the
33 * resources for questions and stick around to help answer questions.
34 * \li \ref asterisk_community_resources
36 * \par Developer Documentation for Asterisk
38 * This is the main developer documentation for Asterisk. It is
39 * generated by running "make progdocs" from the Asterisk source tree.
41 * In addition to the information available on the Asterisk source code,
42 * please see the appendices for information on coding guidelines,
43 * release management, commit policies, and more.
45 * \arg \ref AsteriskArchitecture
47 * \par Additional documentation
50 * \arg \ref configuration_file
51 * \arg \ref channel_drivers
52 * \arg \ref applications
54 * \section copyright Copyright and Author
56 * Copyright (C) 1999 - 2012, Digium, Inc.
57 * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
58 * of <a href="http://www.digium.com">Digium, Inc</a>.
60 * \author Mark Spencer <markster@digium.com>
62 * See http://www.asterisk.org for more information about
63 * the Asterisk project. Please do not directly contact
64 * any of the maintainers of this project for assistance;
65 * the project provides a web site, mailing lists, and IRC
66 * channels for your use.
71 * \page asterisk_community_resources Asterisk Community Resources
73 * \li http://www.asterisk.org Asterisk Homepage
74 * \li http://wiki.asterisk.org Asterisk Wiki
78 * All lists: http://lists.digium.com/mailman/listinfo
79 * \li aadk-commits SVN commits to the AADK repository
80 * \li asterisk-addons-commits SVN commits to the Asterisk addons project
81 * \li asterisk-announce [no description available]
82 * \li asterisk-biz Commercial and Business-Oriented Asterisk Discussion
83 * \li Asterisk-BSD Asterisk on BSD discussion
84 * \li asterisk-bugs [no description available]
85 * \li asterisk-commits SVN commits to the Asterisk project
86 * \li asterisk-dev Asterisk Developers Mailing List
87 * \li asterisk-doc Discussions regarding The Asterisk Documentation Project
88 * \li asterisk-embedded Asterisk Embedded Development
89 * \li asterisk-gui Asterisk GUI project discussion
90 * \li asterisk-gui-commits SVN commits to the Asterisk-GUI project
91 * \li asterisk-ha-clustering Asterisk High Availability and Clustering List - Non-Commercial Discussion
92 * \li Asterisk-i18n Discussion of Asterisk internationalization
93 * \li asterisk-r2 [no description available]
94 * \li asterisk-scf-commits Commits to the Asterisk SCF project code repositories
95 * \li asterisk-scf-committee Asterisk SCF Steering Committee discussions
96 * \li asterisk-scf-dev Asterisk SCF Developers Mailing List
97 * \li asterisk-scf-wiki-changes Changes to the Asterisk SCF space on wiki.asterisk.org
98 * \li asterisk-security Asterisk Security Discussion
99 * \li asterisk-speech-rec Use of speech recognition in Asterisk
100 * \li asterisk-ss7 [no description available]
101 * \li asterisk-users Asterisk Users Mailing List - Non-Commercial Discussion
102 * \li asterisk-video Development discussion of video media support in Asterisk
103 * \li asterisk-wiki-changes Changes to the Asterisk space on wiki.asterisk.org
104 * \li asterisknow AsteriskNOW Discussion
105 * \li dahdi-commits SVN commits to the DAHDI project
106 * \li digium-announce Digium Product Announcements
107 * \li Dundi Distributed Universal Number Discovery
108 * \li libiax2-commits SVN commits to the libiax2 project
109 * \li libpri-commits SVN commits to the libpri project
110 * \li libss7-commits SVN commits to the libss7 project
111 * \li svn-commits SVN commits to the Digium repositories
112 * \li Test-results Results from automated testing
113 * \li thirdparty-commits SVN commits to the Digium third-party software repository
114 * \li zaptel-commits SVN commits to the Zaptel project
117 * \li Forums are located at http://forums.asterisk.org/
121 * Use http://www.freenode.net IRC server to connect with Asterisk
122 * developers and users in realtime.
124 * \li \verbatim #asterisk \endverbatim Asterisk Users Room
125 * \li \verbatim #asterisk-dev \endverbatim Asterisk Developers Room
129 * If you would like to add a resource to this list please create an issue
130 * on the issue tracker with a patch.
134 * \brief Top level source file for Asterisk - the Open Source PBX.
135 * Implementation of PBX core functions and CLI interface.
138 /*! \li \ref asterisk.c uses the configuration file \ref asterisk.conf
139 * \addtogroup configuration_file
142 /*! \page asterisk.conf asterisk.conf
143 * \verbinclude asterisk.conf.sample
147 <support_level>core</support_level>
150 #include "asterisk.h"
152 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
154 #include "asterisk/_private.h"
156 #undef sched_setscheduler
158 #include <sys/time.h>
163 #include <sys/wait.h>
165 #include <sys/resource.h>
168 #include <sys/stat.h>
169 #if defined(HAVE_SYSINFO)
170 #include <sys/sysinfo.h>
171 #elif defined(HAVE_SYSCTL)
172 #include <sys/param.h>
173 #include <sys/sysctl.h>
174 #if !defined(__OpenBSD__)
175 #include <sys/vmmeter.h>
176 #if defined(__FreeBSD__)
177 #include <vm/vm_param.h>
180 #if defined(HAVE_SWAPCTL)
181 #include <sys/swap.h>
185 #include <histedit.h>
188 int daemon(int, int); /* defined in libresolv of all places */
189 #include <sys/loadavg.h>
193 #include <sys/prctl.h>
195 #include <sys/capability.h>
196 #endif /* HAVE_CAP */
199 /* we define here the variables so to better agree on the prototype */
200 #include "asterisk/paths.h"
201 #include "asterisk/network.h"
202 #include "asterisk/cli.h"
203 #include "asterisk/channel.h"
204 #include "asterisk/translate.h"
205 #include "asterisk/features.h"
206 #include "asterisk/acl.h"
207 #include "asterisk/ulaw.h"
208 #include "asterisk/alaw.h"
209 #include "asterisk/callerid.h"
210 #include "asterisk/image.h"
211 #include "asterisk/tdd.h"
212 #include "asterisk/term.h"
213 #include "asterisk/manager.h"
214 #include "asterisk/cdr.h"
215 #include "asterisk/cel.h"
216 #include "asterisk/pbx.h"
217 #include "asterisk/enum.h"
218 #include "asterisk/http.h"
219 #include "asterisk/udptl.h"
220 #include "asterisk/app.h"
221 #include "asterisk/lock.h"
222 #include "asterisk/utils.h"
223 #include "asterisk/file.h"
224 #include "asterisk/io.h"
225 #include "editline/histedit.h"
226 #include "asterisk/config.h"
227 #include "asterisk/ast_version.h"
228 #include "asterisk/linkedlists.h"
229 #include "asterisk/devicestate.h"
230 #include "asterisk/presencestate.h"
231 #include "asterisk/module.h"
232 #include "asterisk/dsp.h"
233 #include "asterisk/buildinfo.h"
234 #include "asterisk/xmldoc.h"
235 #include "asterisk/poll-compat.h"
236 #include "asterisk/ccss.h"
237 #include "asterisk/test.h"
238 #include "asterisk/rtp_engine.h"
239 #include "asterisk/format.h"
240 #include "asterisk/aoc.h"
242 #include "../defaults.h"
248 #define AF_LOCAL AF_UNIX
249 #define PF_LOCAL PF_UNIX
252 #define AST_MAX_CONNECTS 128
255 /*! Default minimum DTMF digit length - 80ms */
256 #define AST_MIN_DTMF_DURATION 80
259 /*! \brief Welcome message when starting a CLI interface */
260 #define WELCOME_MESSAGE \
261 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
262 "Created by Mark Spencer <markster@digium.com>\n" \
263 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
264 "This is free software, with components licensed under the GNU General Public\n" \
265 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
266 "certain conditions. Type 'core show license' for details.\n" \
267 "=========================================================================\n", ast_get_version()) \
269 /*! \defgroup main_options Main Configuration Options
270 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
271 * \arg \ref Config_ast "asterisk.conf"
272 * \note Some of them can be changed in the CLI
276 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
277 struct ast_flags ast_compat = { 0 };
279 int option_verbose; /*!< Verbosity level */
280 int option_debug; /*!< Debug level */
281 double option_maxload; /*!< Max load avg on system */
282 int option_maxcalls; /*!< Max number of active calls */
283 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
284 unsigned int option_dtmfminduration; /*!< Minimum duration of DTMF. */
285 #if defined(HAVE_SYSINFO)
286 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
291 struct ast_eid ast_eid_default;
293 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
294 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
296 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
297 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
300 int fd; /*!< File descriptor */
301 int p[2]; /*!< Pipe */
302 pthread_t t; /*!< Thread of handler */
303 int mute; /*!< Is the console muted for logs */
304 int uid; /*!< Remote user ID. */
305 int gid; /*!< Remote group ID. */
306 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
311 AST_RWLIST_ENTRY(ast_atexit) list;
314 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
316 struct timeval ast_startuptime;
317 struct timeval ast_lastreloadtime;
319 static History *el_hist;
321 static char *remotehostname;
323 struct console consoles[AST_MAX_CONNECTS];
325 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
327 static int ast_el_add_history(char *);
328 static int ast_el_read_history(char *);
329 static int ast_el_write_history(char *);
332 char config_dir[PATH_MAX];
333 char module_dir[PATH_MAX];
334 char spool_dir[PATH_MAX];
335 char monitor_dir[PATH_MAX];
336 char var_dir[PATH_MAX];
337 char data_dir[PATH_MAX];
338 char log_dir[PATH_MAX];
339 char agi_dir[PATH_MAX];
340 char run_dir[PATH_MAX];
341 char key_dir[PATH_MAX];
343 char config_file[PATH_MAX];
344 char db_path[PATH_MAX];
345 char sbin_dir[PATH_MAX];
346 char pid_path[PATH_MAX];
347 char socket_path[PATH_MAX];
348 char run_user[PATH_MAX];
349 char run_group[PATH_MAX];
350 char system_name[128];
353 static struct _cfg_paths cfg_paths;
355 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
356 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
357 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
358 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
359 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
360 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
361 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
362 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
363 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
364 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
365 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
366 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
368 const char *ast_config_AST_DB = cfg_paths.db_path;
369 const char *ast_config_AST_PID = cfg_paths.pid_path;
370 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
371 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
372 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
373 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
375 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
376 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
377 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
378 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
380 extern unsigned int ast_FD_SETSIZE;
382 static char *_argv[256];
384 NOT_SHUTTING_DOWN = -2,
386 /* Valid values for quit_handler niceness below: */
392 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
393 static int restartnow;
394 static pthread_t consolethread = AST_PTHREADT_NULL;
395 static pthread_t mon_sig_flags;
396 static int canary_pid = 0;
397 static char canary_filename[128];
398 static int multi_thread_safe;
400 static char randompool[256];
402 static int sig_alert_pipe[2] = { -1, -1 };
404 unsigned int need_reload:1;
405 unsigned int need_quit:1;
406 unsigned int need_quit_handler:1;
409 #if !defined(LOW_MEMORY)
410 struct file_version {
411 AST_RWLIST_ENTRY(file_version) list;
416 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
418 void ast_register_file_version(const char *file, const char *version)
420 struct file_version *new;
422 size_t version_length;
424 work = ast_strdupa(version);
425 work = ast_strip(ast_strip_quoted(work, "$", "$"));
426 version_length = strlen(work) + 1;
428 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
432 new->version = (char *) new + sizeof(*new);
433 memcpy(new->version, work, version_length);
434 AST_RWLIST_WRLOCK(&file_versions);
435 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
436 AST_RWLIST_UNLOCK(&file_versions);
439 void ast_unregister_file_version(const char *file)
441 struct file_version *find;
443 AST_RWLIST_WRLOCK(&file_versions);
444 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
445 if (!strcasecmp(find->file, file)) {
446 AST_RWLIST_REMOVE_CURRENT(list);
450 AST_RWLIST_TRAVERSE_SAFE_END;
451 AST_RWLIST_UNLOCK(&file_versions);
457 char *ast_complete_source_filename(const char *partial, int n)
459 struct file_version *find;
460 size_t len = strlen(partial);
464 AST_RWLIST_RDLOCK(&file_versions);
465 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
466 if (!strncasecmp(find->file, partial, len) && ++count > n) {
467 res = ast_strdup(find->file);
471 AST_RWLIST_UNLOCK(&file_versions);
475 /*! \brief Find version for given module name */
476 const char *ast_file_version_find(const char *file)
478 struct file_version *iterator;
480 AST_RWLIST_WRLOCK(&file_versions);
481 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
482 if (!strcasecmp(iterator->file, file))
485 AST_RWLIST_UNLOCK(&file_versions);
487 return iterator->version;
491 struct thread_list_t {
492 AST_RWLIST_ENTRY(thread_list_t) list;
498 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
500 void ast_register_thread(char *name)
502 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
507 ast_assert(multi_thread_safe);
508 new->id = pthread_self();
509 new->lwp = ast_get_tid();
510 new->name = name; /* steal the allocated memory for the thread name */
511 AST_RWLIST_WRLOCK(&thread_list);
512 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
513 AST_RWLIST_UNLOCK(&thread_list);
516 void ast_unregister_thread(void *id)
518 struct thread_list_t *x;
520 AST_RWLIST_WRLOCK(&thread_list);
521 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
522 if ((void *) x->id == id) {
523 AST_RWLIST_REMOVE_CURRENT(list);
527 AST_RWLIST_TRAVERSE_SAFE_END;
528 AST_RWLIST_UNLOCK(&thread_list);
535 /*! \brief Give an overview of core settings */
536 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
544 e->command = "core show settings";
545 e->usage = "Usage: core show settings\n"
546 " Show core misc settings";
552 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
554 ast_cli(a->fd, "\nPBX Core settings\n");
555 ast_cli(a->fd, "-----------------\n");
556 ast_cli(a->fd, " Version: %s\n", ast_get_version());
557 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
559 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
561 ast_cli(a->fd, " Maximum calls: Not set\n");
563 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
565 ast_cli(a->fd, " Maximum open file handles: Not set\n");
566 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
567 ast_cli(a->fd, " Debug level: %d\n", option_debug);
568 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
569 #if defined(HAVE_SYSINFO)
570 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
572 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
573 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
574 ast_cli(a->fd, " Startup time: %s\n", buf);
576 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
577 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
578 ast_cli(a->fd, " Last reload time: %s\n", buf);
580 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);
581 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
582 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
583 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
584 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
585 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
586 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
587 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
588 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
589 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
590 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
591 ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
593 ast_cli(a->fd, "\n* Subsystems\n");
594 ast_cli(a->fd, " -------------\n");
595 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
596 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
597 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
598 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
600 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
602 ast_cli(a->fd, "\n* Directories\n");
603 ast_cli(a->fd, " -------------\n");
604 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
605 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
606 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
607 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
608 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
609 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
610 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
611 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
612 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
613 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
614 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
615 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
616 ast_cli(a->fd, "\n\n");
620 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
623 struct thread_list_t *cur;
626 e->command = "core show threads";
628 "Usage: core show threads\n"
629 " List threads currently active in the system.\n";
635 AST_RWLIST_RDLOCK(&thread_list);
636 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
637 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
640 AST_RWLIST_UNLOCK(&thread_list);
641 ast_cli(a->fd, "%d threads listed.\n", count);
645 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
647 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
648 * to be based on the new swapctl(2) system call.
650 static int swapmode(int *used, int *total)
652 struct swapent *swdev;
653 int nswap, rnswap, i;
655 nswap = swapctl(SWAP_NSWAP, 0, 0);
659 swdev = ast_calloc(nswap, sizeof(*swdev));
663 rnswap = swapctl(SWAP_STATS, swdev, nswap);
669 /* if rnswap != nswap, then what? */
671 /* Total things up */
673 for (i = 0; i < nswap; i++) {
674 if (swdev[i].se_flags & SWF_ENABLE) {
675 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
676 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
682 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
683 static int swapmode(int *used, int *total)
690 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
691 /*! \brief Give an overview of system statistics */
692 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
694 uint64_t physmem, freeram;
695 uint64_t freeswap = 0;
699 #if defined(HAVE_SYSINFO)
700 struct sysinfo sys_info;
702 uptime = sys_info.uptime / 3600;
703 physmem = sys_info.totalram * sys_info.mem_unit;
704 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
705 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
706 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
707 nprocs = sys_info.procs;
708 #elif defined(HAVE_SYSCTL)
709 static int pageshift;
710 struct vmtotal vmtotal;
711 struct timeval boottime;
713 int mib[2], pagesize, usedswap = 0;
715 /* calculate the uptime by looking at boottime */
718 mib[1] = KERN_BOOTTIME;
719 len = sizeof(boottime);
720 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
721 uptime = now - boottime.tv_sec;
723 uptime = uptime/3600;
724 /* grab total physical memory */
726 #if defined(HW_PHYSMEM64)
727 mib[1] = HW_PHYSMEM64;
731 len = sizeof(physmem);
732 sysctl(mib, 2, &physmem, &len, NULL, 0);
734 pagesize = getpagesize();
736 while (pagesize > 1) {
741 /* we only need the amount of log(2)1024 for our conversion */
747 len = sizeof(vmtotal);
748 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
749 freeram = (vmtotal.t_free << pageshift);
750 /* generate swap usage and totals */
751 swapmode(&usedswap, &totalswap);
752 freeswap = (totalswap - usedswap);
753 /* grab number of processes */
754 #if defined(__OpenBSD__)
756 mib[1] = KERN_NPROCS;
757 len = sizeof(nprocs);
758 sysctl(mib, 2, &nprocs, &len, NULL, 0);
764 e->command = "core show sysinfo";
766 "Usage: core show sysinfo\n"
767 " List current system information.\n";
773 ast_cli(a->fd, "\nSystem Statistics\n");
774 ast_cli(a->fd, "-----------------\n");
775 ast_cli(a->fd, " System Uptime: %lu hours\n", uptime);
776 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
777 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
778 #if defined(HAVE_SYSINFO)
779 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
781 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
782 ast_cli(a->fd, " Total Swap Space: %u KiB\n", totalswap);
783 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
785 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
790 struct profile_entry {
792 uint64_t scale; /* if non-zero, values are scaled by this */
798 struct profile_data {
801 struct profile_entry e[0];
804 static struct profile_data *prof_data;
806 /*! \brief allocates a counter with a given name and scale.
807 * \return Returns the identifier of the counter.
809 int ast_add_profile(const char *name, uint64_t scale)
811 int l = sizeof(struct profile_data);
812 int n = 10; /* default entries */
814 if (prof_data == NULL) {
815 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
816 if (prof_data == NULL)
818 prof_data->entries = 0;
819 prof_data->max_size = n;
821 if (prof_data->entries >= prof_data->max_size) {
823 n = prof_data->max_size + 20;
824 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
828 prof_data->max_size = n;
830 n = prof_data->entries++;
831 prof_data->e[n].name = ast_strdup(name);
832 prof_data->e[n].value = 0;
833 prof_data->e[n].events = 0;
834 prof_data->e[n].mark = 0;
835 prof_data->e[n].scale = scale;
839 int64_t ast_profile(int i, int64_t delta)
841 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
843 if (prof_data->e[i].scale > 1)
844 delta /= prof_data->e[i].scale;
845 prof_data->e[i].value += delta;
846 prof_data->e[i].events++;
847 return prof_data->e[i].value;
850 /* The RDTSC instruction was introduced on the Pentium processor and is not
851 * implemented on certain clones, like the Cyrix 586. Hence, the previous
852 * expectation of __i386__ was in error. */
853 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
854 #if defined(__FreeBSD__)
855 #include <machine/cpufunc.h>
857 static __inline uint64_t
862 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
866 #else /* supply a dummy function on other platforms */
867 static __inline uint64_t
874 int64_t ast_mark(int i, int startstop)
876 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
879 prof_data->e[i].mark = rdtsc();
881 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
882 if (prof_data->e[i].scale > 1)
883 prof_data->e[i].mark /= prof_data->e[i].scale;
884 prof_data->e[i].value += prof_data->e[i].mark;
885 prof_data->e[i].events++;
887 return prof_data->e[i].mark;
890 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
891 max = prof_data->entries;\
892 if (a->argc > 3) { /* specific entries */ \
893 if (isdigit(a->argv[3][0])) { \
894 min = atoi(a->argv[3]); \
895 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
896 max = atoi(a->argv[4]); \
898 search = a->argv[3]; \
900 if (max > prof_data->entries) \
901 max = prof_data->entries;
903 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
906 const char *search = NULL;
909 e->command = "core show profile";
910 e->usage = "Usage: core show profile\n"
911 " show profile information";
917 if (prof_data == NULL)
920 DEFINE_PROFILE_MIN_MAX_VALUES;
921 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
922 prof_data->entries, prof_data->max_size);
923 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
924 "Value", "Average", "Name");
925 for (i = min; i < max; i++) {
926 struct profile_entry *entry = &prof_data->e[i];
927 if (!search || strstr(entry->name, search))
928 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
931 (long)entry->events, (long long)entry->value,
932 (long long)(entry->events ? entry->value / entry->events : entry->value),
938 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
941 const char *search = NULL;
944 e->command = "core clear profile";
945 e->usage = "Usage: core clear profile\n"
946 " clear profile information";
952 if (prof_data == NULL)
955 DEFINE_PROFILE_MIN_MAX_VALUES;
956 for (i= min; i < max; i++) {
957 if (!search || strstr(prof_data->e[i].name, search)) {
958 prof_data->e[i].value = 0;
959 prof_data->e[i].events = 0;
964 #undef DEFINE_PROFILE_MIN_MAX_VALUES
966 /*! \brief CLI command to list module versions */
967 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
969 #define FORMAT "%-25.25s %-40.40s\n"
970 struct file_version *iterator;
976 int matchlen, which = 0;
977 struct file_version *find;
981 e->command = "core show file version [like]";
983 "Usage: core show file version [like <pattern>]\n"
984 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
985 " Optional regular expression pattern is used to filter the file list.\n";
988 matchlen = strlen(a->word);
991 AST_RWLIST_RDLOCK(&file_versions);
992 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
993 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
994 ret = ast_strdup(find->file);
998 AST_RWLIST_UNLOCK(&file_versions);
1005 if (!strcasecmp(a->argv[4], "like")) {
1006 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
1007 return CLI_SHOWUSAGE;
1010 return CLI_SHOWUSAGE;
1018 return CLI_SHOWUSAGE;
1021 ast_cli(a->fd, FORMAT, "File", "Revision");
1022 ast_cli(a->fd, FORMAT, "----", "--------");
1023 AST_RWLIST_RDLOCK(&file_versions);
1024 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
1025 if (havename && strcasecmp(iterator->file, a->argv[4]))
1028 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
1031 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
1036 AST_RWLIST_UNLOCK(&file_versions);
1038 ast_cli(a->fd, "%d files listed.\n", count_files);
1048 #endif /* ! LOW_MEMORY */
1050 int ast_register_atexit(void (*func)(void))
1052 struct ast_atexit *ae;
1054 if (!(ae = ast_calloc(1, sizeof(*ae))))
1059 ast_unregister_atexit(func);
1061 AST_RWLIST_WRLOCK(&atexits);
1062 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
1063 AST_RWLIST_UNLOCK(&atexits);
1068 void ast_unregister_atexit(void (*func)(void))
1070 struct ast_atexit *ae = NULL;
1072 AST_RWLIST_WRLOCK(&atexits);
1073 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1074 if (ae->func == func) {
1075 AST_RWLIST_REMOVE_CURRENT(list);
1079 AST_RWLIST_TRAVERSE_SAFE_END;
1080 AST_RWLIST_UNLOCK(&atexits);
1085 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1086 static int fdsend(int fd, const char *s)
1088 return write(fd, s, strlen(s) + 1);
1091 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1092 static int fdprint(int fd, const char *s)
1094 return write(fd, s, strlen(s));
1097 /*! \brief NULL handler so we can collect the child exit status */
1098 static void _null_sig_handler(int sig)
1102 static struct sigaction null_sig_handler = {
1103 .sa_handler = _null_sig_handler,
1104 .sa_flags = SA_RESTART,
1107 static struct sigaction ignore_sig_handler = {
1108 .sa_handler = SIG_IGN,
1111 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1112 /*! \brief Keep track of how many threads are currently trying to wait*() on
1115 static unsigned int safe_system_level = 0;
1116 static struct sigaction safe_system_prev_handler;
1118 void ast_replace_sigchld(void)
1122 ast_mutex_lock(&safe_system_lock);
1123 level = safe_system_level++;
1125 /* only replace the handler if it has not already been done */
1127 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1130 ast_mutex_unlock(&safe_system_lock);
1133 void ast_unreplace_sigchld(void)
1137 ast_mutex_lock(&safe_system_lock);
1138 level = --safe_system_level;
1140 /* only restore the handler if we are the last one */
1142 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1145 ast_mutex_unlock(&safe_system_lock);
1148 int ast_safe_system(const char *s)
1152 struct rusage rusage;
1155 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1156 ast_replace_sigchld();
1158 #ifdef HAVE_WORKING_FORK
1166 cap_t cap = cap_from_text("cap_net_admin-eip");
1168 if (cap_set_proc(cap)) {
1169 /* Careful with order! Logging cannot happen after we close FDs */
1170 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1174 #ifdef HAVE_WORKING_FORK
1175 if (ast_opt_high_priority)
1176 ast_set_priority(0);
1177 /* Close file descriptors and launch system command */
1178 ast_close_fds_above_n(STDERR_FILENO);
1180 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1182 } else if (pid > 0) {
1184 res = wait4(pid, &status, 0, &rusage);
1186 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1188 } else if (errno != EINTR)
1192 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1196 ast_unreplace_sigchld();
1197 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1205 * \brief enable or disable a logging level to a specified console
1207 void ast_console_toggle_loglevel(int fd, int level, int state)
1211 if (level >= NUMLOGLEVELS) {
1212 level = NUMLOGLEVELS - 1;
1215 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1216 if (fd == consoles[x].fd) {
1218 * Since the logging occurs when levels are false, set to
1219 * flipped iinput because this function accepts 0 as off and 1 as on
1221 consoles[x].levels[level] = state ? 0 : 1;
1228 * \brief mute or unmute a console from logging
1230 void ast_console_toggle_mute(int fd, int silent)
1233 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1234 if (fd == consoles[x].fd) {
1235 if (consoles[x].mute) {
1236 consoles[x].mute = 0;
1238 ast_cli(fd, "Console is not muted anymore.\n");
1240 consoles[x].mute = 1;
1242 ast_cli(fd, "Console is muted.\n");
1247 ast_cli(fd, "Couldn't find remote console.\n");
1251 * \brief log the string to all attached console clients
1253 static void ast_network_puts_mutable(const char *string, int level)
1256 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1257 if (consoles[x].mute)
1259 if (consoles[x].fd > -1) {
1260 if (!consoles[x].levels[level])
1261 fdprint(consoles[x].p[1], string);
1267 * \brief log the string to the console, and all attached
1270 void ast_console_puts_mutable(const char *string, int level)
1272 fputs(string, stdout);
1274 ast_network_puts_mutable(string, level);
1278 * \brief write the string to all attached console clients
1280 static void ast_network_puts(const char *string)
1283 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1284 if (consoles[x].fd > -1)
1285 fdprint(consoles[x].p[1], string);
1290 * \brief write the string to the console, and all attached
1293 void ast_console_puts(const char *string)
1295 fputs(string, stdout);
1297 ast_network_puts(string);
1300 static void network_verboser(const char *s)
1302 ast_network_puts_mutable(s, __LOG_VERBOSE);
1305 static pthread_t lthread;
1308 * \brief read() function supporting the reception of user credentials.
1310 * \param fd Socket file descriptor.
1311 * \param buffer Receive buffer.
1312 * \param size 'buffer' size.
1313 * \param con Console structure to set received credentials
1314 * \retval -1 on error
1315 * \retval the number of bytes received on success.
1317 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1319 #if defined(SO_PEERCRED)
1320 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1321 #define HAVE_STRUCT_UCRED_UID
1322 struct sockpeercred cred;
1326 socklen_t len = sizeof(cred);
1328 #if defined(HAVE_GETPEEREID)
1336 result = read(fd, buffer, size);
1341 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1342 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1345 #if defined(HAVE_STRUCT_UCRED_UID)
1348 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1351 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1353 #elif defined(HAVE_GETPEEREID)
1354 if (getpeereid(fd, &uid, &gid)) {
1366 static void *netconsole(void *vconsole)
1368 struct console *con = vconsole;
1369 char hostname[MAXHOSTNAMELEN] = "";
1372 const char * const end_buf = inbuf + sizeof(inbuf);
1373 char *start_read = inbuf;
1375 struct pollfd fds[2];
1377 if (gethostname(hostname, sizeof(hostname)-1))
1378 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1379 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1380 fdprint(con->fd, outbuf);
1382 fds[0].fd = con->fd;
1383 fds[0].events = POLLIN;
1385 fds[1].fd = con->p[0];
1386 fds[1].events = POLLIN;
1389 res = ast_poll(fds, 2, -1);
1392 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1395 if (fds[0].revents) {
1396 int cmds_read, bytes_read;
1397 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1400 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1401 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1402 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1405 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1406 * NULL and not trailing partial commands. */
1407 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1408 /* No commands were read. We either have a short read on the first command
1409 * with space left, or a command that is too long */
1410 if (start_read + bytes_read < end_buf) {
1411 start_read += bytes_read;
1413 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1418 if (start_read[bytes_read - 1] == '\0') {
1419 /* The read ended on a command boundary, start reading again at the head of inbuf */
1423 /* If we get this far, we have left over characters that have not been processed.
1424 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1425 * We are guaranteed to have at least cmds_read NULLs */
1426 while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1429 memmove(inbuf, start_read, end_buf - start_read);
1430 start_read = end_buf - start_read + inbuf;
1432 if (fds[1].revents) {
1433 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1435 ast_log(LOG_ERROR, "read returned %d\n", res);
1438 res = write(con->fd, outbuf, res);
1443 if (!ast_opt_hide_connect) {
1444 ast_verb(3, "Remote UNIX connection disconnected\n");
1454 static void *listener(void *unused)
1456 struct sockaddr_un sunaddr;
1461 struct pollfd fds[1];
1465 fds[0].fd = ast_socket;
1466 fds[0].events = POLLIN;
1467 s = ast_poll(fds, 1, -1);
1468 pthread_testcancel();
1471 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1474 len = sizeof(sunaddr);
1475 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1478 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1480 #if !defined(SO_PASSCRED)
1484 /* turn on socket credentials passing. */
1485 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1486 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1489 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1490 if (consoles[x].fd >= 0) {
1493 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1494 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1495 consoles[x].fd = -1;
1496 fdprint(s, "Server failed to create pipe\n");
1500 flags = fcntl(consoles[x].p[1], F_GETFL);
1501 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1503 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1504 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1505 to know if the user didn't send the credentials. */
1506 consoles[x].uid = -2;
1507 consoles[x].gid = -2;
1508 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1509 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1510 close(consoles[x].p[0]);
1511 close(consoles[x].p[1]);
1512 consoles[x].fd = -1;
1513 fdprint(s, "Server failed to spawn thread\n");
1518 if (x >= AST_MAX_CONNECTS) {
1519 fdprint(s, "No more connections allowed\n");
1520 ast_log(LOG_WARNING, "No more connections allowed\n");
1522 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1523 ast_verb(3, "Remote UNIX connection\n");
1531 static int ast_makesocket(void)
1533 struct sockaddr_un sunaddr;
1539 for (x = 0; x < AST_MAX_CONNECTS; x++)
1540 consoles[x].fd = -1;
1541 unlink(ast_config_AST_SOCKET);
1542 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1543 if (ast_socket < 0) {
1544 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1547 memset(&sunaddr, 0, sizeof(sunaddr));
1548 sunaddr.sun_family = AF_LOCAL;
1549 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1550 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1552 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1557 res = listen(ast_socket, 2);
1559 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1564 if (ast_register_verbose(network_verboser)) {
1565 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1568 if (ast_pthread_create_background(<hread, NULL, listener, NULL)) {
1569 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1574 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1576 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1577 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1582 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1584 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1585 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1590 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1591 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1593 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1596 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1598 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1599 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1605 static int ast_tryconnect(void)
1607 struct sockaddr_un sunaddr;
1609 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1610 if (ast_consock < 0) {
1611 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1614 memset(&sunaddr, 0, sizeof(sunaddr));
1615 sunaddr.sun_family = AF_LOCAL;
1616 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1617 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1626 /*! \brief Urgent handler
1628 * Called by soft_hangup to interrupt the poll, read, or other
1629 * system call. We don't actually need to do anything though.
1630 * Remember: Cannot EVER ast_log from within a signal handler
1632 static void _urg_handler(int num)
1637 static struct sigaction urg_handler = {
1638 .sa_handler = _urg_handler,
1639 .sa_flags = SA_RESTART,
1642 static void _hup_handler(int num)
1644 int a = 0, save_errno = errno;
1645 printf("Received HUP signal -- Reloading configs\n");
1647 execvp(_argv[0], _argv);
1648 sig_flags.need_reload = 1;
1649 if (sig_alert_pipe[1] != -1) {
1650 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1651 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1657 static struct sigaction hup_handler = {
1658 .sa_handler = _hup_handler,
1659 .sa_flags = SA_RESTART,
1662 static void _child_handler(int sig)
1664 /* Must not ever ast_log or ast_verbose within signal handler */
1665 int n, status, save_errno = errno;
1668 * Reap all dead children -- not just one
1670 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1672 if (n == 0 && option_debug)
1673 printf("Huh? Child handler, but nobody there?\n");
1677 static struct sigaction child_handler = {
1678 .sa_handler = _child_handler,
1679 .sa_flags = SA_RESTART,
1682 /*! \brief Set maximum open files */
1683 static void set_ulimit(int value)
1685 struct rlimit l = {0, 0};
1688 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1695 if (setrlimit(RLIMIT_NOFILE, &l)) {
1696 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1700 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1705 /*! \brief Set an X-term or screen title */
1706 static void set_title(char *text)
1708 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1709 fprintf(stdout, "\033]2;%s\007", text);
1712 static void set_icon(char *text)
1714 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1715 fprintf(stdout, "\033]1;%s\007", text);
1718 /*! \brief We set ourselves to a high priority, that we might pre-empt
1719 * everything else. If your PBX has heavy activity on it, this is a
1722 int ast_set_priority(int pri)
1724 struct sched_param sched;
1725 memset(&sched, 0, sizeof(sched));
1728 sched.sched_priority = 10;
1729 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1730 ast_log(LOG_WARNING, "Unable to set high priority\n");
1733 ast_verb(1, "Set to realtime thread\n");
1735 sched.sched_priority = 0;
1736 /* According to the manpage, these parameters can never fail. */
1737 sched_setscheduler(0, SCHED_OTHER, &sched);
1741 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1742 ast_log(LOG_WARNING, "Unable to set high priority\n");
1745 ast_verb(1, "Set to high priority\n");
1747 /* According to the manpage, these parameters can never fail. */
1748 setpriority(PRIO_PROCESS, 0, 0);
1754 static void ast_run_atexits(void)
1756 struct ast_atexit *ae;
1757 AST_RWLIST_RDLOCK(&atexits);
1758 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1762 AST_RWLIST_UNLOCK(&atexits);
1765 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1766 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1768 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1770 if (can_safely_quit(niceness, restart)) {
1771 really_quit(num, niceness, restart);
1772 /* No one gets here. */
1774 /* It wasn't our time. */
1777 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1779 /* Check if someone else isn't already doing this. */
1780 ast_mutex_lock(&safe_system_lock);
1781 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1782 /* Already in progress and other request was less nice. */
1783 ast_mutex_unlock(&safe_system_lock);
1784 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1787 shuttingdown = niceness;
1788 ast_mutex_unlock(&safe_system_lock);
1790 /* Try to get as many CDRs as possible submitted to the backend engines
1791 * (if in batch mode). really_quit happens to call it again when running
1792 * the atexit handlers, otherwise this would be a bit early. */
1793 ast_cdr_engine_term();
1795 /* Shutdown the message queue for the technology agnostic message channel.
1796 * This has to occur before we pause shutdown pending ast_undestroyed_channels. */
1799 if (niceness == SHUTDOWN_NORMAL) {
1801 /* Begin shutdown routine, hanging up active channels */
1802 ast_begin_shutdown(1);
1803 if (option_verbose && ast_opt_console) {
1804 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1809 /* Wait up to 15 seconds for all channels to go away */
1810 if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1813 /* Sleep 1/10 of a second */
1816 } else if (niceness >= SHUTDOWN_NICE) {
1817 if (niceness != SHUTDOWN_REALLY_NICE) {
1818 ast_begin_shutdown(0);
1820 if (option_verbose && ast_opt_console) {
1821 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1824 if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1831 /* Re-acquire lock and check if someone changed the niceness, in which
1832 * case someone else has taken over the shutdown.
1834 ast_mutex_lock(&safe_system_lock);
1835 if (shuttingdown != niceness) {
1836 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1837 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1839 ast_mutex_unlock(&safe_system_lock);
1842 shuttingdown = SHUTTING_DOWN;
1843 ast_mutex_unlock(&safe_system_lock);
1848 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1850 if (niceness >= SHUTDOWN_NICE) {
1851 ast_module_shutdown();
1854 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1855 char filename[80] = "";
1856 if (getenv("HOME")) {
1857 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1859 if (!ast_strlen_zero(filename)) {
1860 ast_el_write_history(filename);
1862 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1863 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1867 if (el_hist != NULL) {
1868 history_end(el_hist);
1870 } else if (mon_sig_flags == pthread_self()) {
1871 if (consolethread != AST_PTHREADT_NULL) {
1872 pthread_kill(consolethread, SIGURG);
1876 /* The manager event for shutdown must happen prior to ast_run_atexits, as
1877 * the manager interface will dispose of its sessions as part of its
1881 <managerEventInstance>
1882 <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
1884 <parameter name="Shutdown">
1886 <enum name="Uncleanly"/>
1887 <enum name="Cleanly"/>
1890 <parameter name="Restart">
1893 <enum name="False"/>
1897 </managerEventInstance>
1899 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\n"
1901 ast_active_channels() ? "Uncleanly" : "Cleanly",
1902 restart ? "True" : "False");
1904 ast_verb(0, "Executing last minute cleanups\n");
1906 /* Called on exit */
1907 ast_verb(0, "Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1908 ast_debug(1, "Asterisk ending (%d).\n", num);
1909 if (ast_socket > -1) {
1910 pthread_cancel(lthread);
1913 unlink(ast_config_AST_SOCKET);
1915 if (ast_consock > -1)
1917 if (!ast_opt_remote)
1918 unlink(ast_config_AST_PID);
1919 printf("%s", term_quit());
1922 ast_verb(0, "Preparing for Asterisk restart...\n");
1923 /* Mark all FD's for closing on exec */
1924 for (i = 3; i < 32768; i++) {
1925 fcntl(i, F_SETFD, FD_CLOEXEC);
1927 ast_verb(0, "Asterisk is now restarting...\n");
1933 /* If there is a consolethread running send it a SIGHUP
1934 so it can execvp, otherwise we can do it ourselves */
1935 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1936 pthread_kill(consolethread, SIGHUP);
1937 /* Give the signal handler some time to complete */
1940 execvp(_argv[0], _argv);
1950 static void __quit_handler(int num)
1953 sig_flags.need_quit = 1;
1954 if (sig_alert_pipe[1] != -1) {
1955 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1956 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1959 /* There is no need to restore the signal handler here, since the app
1960 * is going to exit */
1963 static void __remote_quit_handler(int num)
1965 sig_flags.need_quit = 1;
1968 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1972 if (!strncmp(s, cmp, strlen(cmp))) {
1973 c = s + strlen(cmp);
1974 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1980 /* These gymnastics are due to platforms which designate char as unsigned by
1981 * default. Level is the negative character -- offset by 1, because \0 is the
1983 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
1984 #define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
1986 static void console_verboser(const char *s)
1989 const char *c = NULL;
1992 if (VERBOSE_HASMAGIC(s)) {
1993 level = VERBOSE_MAGIC2LEVEL(s);
1995 if (level > option_verbose) {
2000 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
2001 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
2002 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
2003 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
2012 /* Wake up a poll()ing console */
2013 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2014 pthread_kill(consolethread, SIGURG);
2018 static int ast_all_zeros(char *s)
2028 static void consolehandler(char *s)
2030 printf("%s", term_end());
2033 /* Called when readline data is available */
2034 if (!ast_all_zeros(s))
2035 ast_el_add_history(s);
2036 /* The real handler for bang */
2039 ast_safe_system(s+1);
2041 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2043 ast_cli_command(STDOUT_FILENO, s);
2046 static int remoteconsolehandler(char *s)
2050 /* Called when readline data is available */
2051 if (!ast_all_zeros(s))
2052 ast_el_add_history(s);
2053 /* The real handler for bang */
2056 ast_safe_system(s+1);
2058 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2060 } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2061 int old_verbose = option_verbose;
2062 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2064 if (sscanf(s + 25, "%d", &tmp) != 1) {
2065 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2067 if (tmp > option_verbose) {
2068 option_verbose = tmp;
2070 if (old_verbose != option_verbose) {
2071 fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2073 fprintf(stdout, "Verbosity level unchanged.\n");
2077 if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2078 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2080 if (old_verbose != option_verbose) {
2081 fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2083 fprintf(stdout, "Verbosity level unchanged.\n");
2088 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2089 (s[4] == '\0' || isspace(s[4]))) {
2090 quit_handler(0, SHUTDOWN_FAST, 0);
2097 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2101 e->command = "core show version";
2103 "Usage: core show version\n"
2104 " Shows Asterisk version information.\n";
2111 return CLI_SHOWUSAGE;
2112 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2113 ast_get_version(), ast_build_user, ast_build_hostname,
2114 ast_build_machine, ast_build_os, ast_build_date);
2119 static int handle_quit(int fd, int argc, char *argv[])
2122 return RESULT_SHOWUSAGE;
2123 quit_handler(0, SHUTDOWN_NORMAL, 0);
2124 return RESULT_SUCCESS;
2128 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2132 e->command = "core stop now";
2134 "Usage: core stop now\n"
2135 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2141 if (a->argc != e->args)
2142 return CLI_SHOWUSAGE;
2143 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2147 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2151 e->command = "core stop gracefully";
2153 "Usage: core stop gracefully\n"
2154 " Causes Asterisk to not accept new calls, and exit when all\n"
2155 " active calls have terminated normally.\n";
2161 if (a->argc != e->args)
2162 return CLI_SHOWUSAGE;
2163 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2167 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2171 e->command = "core stop when convenient";
2173 "Usage: core stop when convenient\n"
2174 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2180 if (a->argc != e->args)
2181 return CLI_SHOWUSAGE;
2182 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2183 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2187 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2191 e->command = "core restart now";
2193 "Usage: core restart now\n"
2194 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2201 if (a->argc != e->args)
2202 return CLI_SHOWUSAGE;
2203 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2207 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2211 e->command = "core restart gracefully";
2213 "Usage: core restart gracefully\n"
2214 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2215 " restart when all active calls have ended.\n";
2221 if (a->argc != e->args)
2222 return CLI_SHOWUSAGE;
2223 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2227 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2231 e->command = "core restart when convenient";
2233 "Usage: core restart when convenient\n"
2234 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2240 if (a->argc != e->args)
2241 return CLI_SHOWUSAGE;
2242 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2243 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2247 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2249 int aborting_shutdown = 0;
2253 e->command = "core abort shutdown";
2255 "Usage: core abort shutdown\n"
2256 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2257 " call operations.\n";
2263 if (a->argc != e->args)
2264 return CLI_SHOWUSAGE;
2266 ast_mutex_lock(&safe_system_lock);
2267 if (shuttingdown >= SHUTDOWN_FAST) {
2268 aborting_shutdown = 1;
2269 shuttingdown = NOT_SHUTTING_DOWN;
2271 ast_mutex_unlock(&safe_system_lock);
2273 if (aborting_shutdown) {
2274 ast_cancel_shutdown();
2279 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2285 "Usage: !<command>\n"
2286 " Executes a given shell command\n";
2294 static const char warranty_lines[] = {
2298 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2299 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2300 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2301 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2302 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2303 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2304 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2305 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2306 "REPAIR OR CORRECTION.\n"
2308 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2309 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2310 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2311 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2312 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2313 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2314 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2315 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2316 "POSSIBILITY OF SUCH DAMAGES.\n"
2319 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2323 e->command = "core show warranty";
2325 "Usage: core show warranty\n"
2326 " Shows the warranty (if any) for this copy of Asterisk.\n";
2332 ast_cli(a->fd, "%s", warranty_lines);
2337 static const char license_lines[] = {
2339 "This program is free software; you can redistribute it and/or modify\n"
2340 "it under the terms of the GNU General Public License version 2 as\n"
2341 "published by the Free Software Foundation.\n"
2343 "This program also contains components licensed under other licenses.\n"
2346 "This program is distributed in the hope that it will be useful,\n"
2347 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2348 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2349 "GNU General Public License for more details.\n"
2351 "You should have received a copy of the GNU General Public License\n"
2352 "along with this program; if not, write to the Free Software\n"
2353 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2356 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2360 e->command = "core show license";
2362 "Usage: core show license\n"
2363 " Shows the license(s) for this copy of Asterisk.\n";
2369 ast_cli(a->fd, "%s", license_lines);
2374 #define ASTERISK_PROMPT "*CLI> "
2376 #define ASTERISK_PROMPT2 "%s*CLI> "
2378 static struct ast_cli_entry cli_asterisk[] = {
2379 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2380 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2381 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2382 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2383 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2384 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2385 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2386 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2387 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2388 AST_CLI_DEFINE(handle_version, "Display version info"),
2389 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2390 #if !defined(LOW_MEMORY)
2391 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2392 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2393 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2394 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2396 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2397 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2398 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2399 #endif /* ! LOW_MEMORY */
2402 struct el_read_char_state_struct {
2403 unsigned int line_full:1;
2404 unsigned int prev_line_full:1;
2405 char prev_line_verbosity;
2408 static int el_read_char_state_init(void *ptr)
2410 struct el_read_char_state_struct *state = ptr;
2411 state->line_full = 1;
2412 state->prev_line_full = 1;
2413 state->prev_line_verbosity = 0;
2417 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2419 static int ast_el_read_char(EditLine *editline, char *cp)
2423 struct pollfd fds[2];
2426 #define EL_BUF_SIZE 512
2427 char buf[EL_BUF_SIZE];
2428 struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2432 fds[0].fd = ast_consock;
2433 fds[0].events = POLLIN;
2434 if (!ast_opt_exec) {
2435 fds[1].fd = STDIN_FILENO;
2436 fds[1].events = POLLIN;
2439 res = ast_poll(fds, max, -1);
2441 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2445 fprintf(stderr, "poll failed: %s\n", strerror(errno));
2449 if (!ast_opt_exec && fds[1].revents) {
2450 num_read = read(STDIN_FILENO, cp, 1);
2457 if (fds[0].revents) {
2459 char *curline = buf, *nextline;
2460 res = read(ast_consock, buf, sizeof(buf) - 1);
2461 /* if the remote side disappears exit */
2463 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2464 if (!ast_opt_reconnect) {
2465 quit_handler(0, SHUTDOWN_FAST, 0);
2468 int reconnects_per_second = 20;
2469 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2470 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2471 if (ast_tryconnect()) {
2472 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2473 printf("%s", term_quit());
2476 fdsend(ast_consock, "logger mute silent");
2478 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2481 usleep(1000000 / reconnects_per_second);
2483 if (tries >= 30 * reconnects_per_second) {
2484 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2485 quit_handler(0, SHUTDOWN_FAST, 0);
2493 /* Write over the CLI prompt */
2494 if (!ast_opt_exec && !lastpos) {
2495 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2500 state->prev_line_full = state->line_full;
2501 if ((nextline = strchr(curline, '\n'))) {
2502 state->line_full = 1;
2505 state->line_full = 0;
2506 nextline = strchr(curline, '\0');
2509 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2510 level = VERBOSE_MAGIC2LEVEL(curline);
2512 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2513 /* Non-verbose output */
2516 level = state->prev_line_verbosity;
2518 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2519 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2523 state->prev_line_verbosity = level;
2525 } while (!ast_strlen_zero(curline));
2527 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2539 static struct ast_str *prompt = NULL;
2541 static char *cli_prompt(EditLine *editline)
2546 static int cli_prompt_changes = 0;
2551 if (prompt == NULL) {
2552 prompt = ast_str_create(100);
2553 } else if (!cli_prompt_changes) {
2554 return ast_str_buffer(prompt);
2556 ast_str_reset(prompt);
2559 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2561 struct timeval ts = ast_tvnow();
2562 while (*t != '\0') {
2564 char hostname[MAXHOSTNAMELEN] = "";
2566 struct ast_tm tm = { 0, };
2567 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2571 case 'C': /* color */
2573 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2574 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2576 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2577 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2581 /* If the color has been reset correctly, then there's no need to reset it later */
2582 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2584 case 'd': /* date */
2585 if (ast_localtime(&ts, &tm, NULL)) {
2586 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2587 ast_str_append(&prompt, 0, "%s", tmp);
2588 cli_prompt_changes++;
2591 case 'g': /* group */
2592 if ((gr = getgrgid(getgid()))) {
2593 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2596 case 'h': /* hostname */
2597 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2598 ast_str_append(&prompt, 0, "%s", hostname);
2600 ast_str_append(&prompt, 0, "%s", "localhost");
2603 case 'H': /* short hostname */
2604 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2606 if ((dotptr = strchr(hostname, '.'))) {
2609 ast_str_append(&prompt, 0, "%s", hostname);
2611 ast_str_append(&prompt, 0, "%s", "localhost");
2614 #ifdef HAVE_GETLOADAVG
2615 case 'l': /* load avg */
2617 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2619 getloadavg(list, 3);
2620 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2621 cli_prompt_changes++;
2625 case 's': /* Asterisk system name (from asterisk.conf) */
2626 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2628 case 't': /* time */
2629 if (ast_localtime(&ts, &tm, NULL)) {
2630 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2631 ast_str_append(&prompt, 0, "%s", tmp);
2632 cli_prompt_changes++;
2635 case 'u': /* username */
2636 if ((pw = getpwuid(getuid()))) {
2637 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2640 case '#': /* process console or remote? */
2641 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2643 case '%': /* literal % */
2644 ast_str_append(&prompt, 0, "%c", '%');
2646 case '\0': /* % is last character - prevent bug */
2651 ast_str_append(&prompt, 0, "%c", *t);
2656 /* Force colors back to normal at end */
2657 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2659 } else if (remotehostname) {
2660 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2662 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2665 return ast_str_buffer(prompt);
2668 static char **ast_el_strtoarr(char *buf)
2670 char **match_list = NULL, **match_list_tmp, *retstr;
2671 size_t match_list_len;
2675 while ( (retstr = strsep(&buf, " ")) != NULL) {
2677 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2679 if (matches + 1 >= match_list_len) {
2680 match_list_len <<= 1;
2681 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2682 match_list = match_list_tmp;
2685 ast_free(match_list);
2686 return (char **) NULL;
2690 match_list[matches++] = ast_strdup(retstr);
2694 return (char **) NULL;
2696 if (matches >= match_list_len) {
2697 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2698 match_list = match_list_tmp;
2701 ast_free(match_list);
2702 return (char **) NULL;
2706 match_list[matches] = (char *) NULL;
2711 static int ast_el_sort_compare(const void *i1, const void *i2)
2715 s1 = ((char **)i1)[0];
2716 s2 = ((char **)i2)[0];
2718 return strcasecmp(s1, s2);
2721 static int ast_cli_display_match_list(char **matches, int len, int max)
2723 int i, idx, limit, count;
2724 int screenwidth = 0;
2725 int numoutput = 0, numoutputline = 0;
2727 screenwidth = ast_get_termcols(STDOUT_FILENO);
2729 /* find out how many entries can be put on one line, with two spaces between strings */
2730 limit = screenwidth / (max + 2);
2734 /* how many lines of output */
2735 count = len / limit;
2736 if (count * limit < len)
2741 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2743 for (; count > 0; count--) {
2745 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2747 /* Don't print dupes */
2748 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2750 ast_free(matches[idx]);
2751 matches[idx] = NULL;
2757 fprintf(stdout, "%-*s ", max, matches[idx]);
2758 ast_free(matches[idx]);
2759 matches[idx] = NULL;
2761 if (numoutputline > 0)
2762 fprintf(stdout, "\n");
2769 static char *cli_complete(EditLine *editline, int ch)
2775 int retval = CC_ERROR;
2776 char buf[2048], savechr;
2779 LineInfo *lf = (LineInfo *)el_line(editline);
2781 savechr = *(char *)lf->cursor;
2782 *(char *)lf->cursor = '\0';
2783 ptr = (char *)lf->cursor;
2785 while (ptr > lf->buffer) {
2786 if (isspace(*ptr)) {
2794 len = lf->cursor - ptr;
2796 if (ast_opt_remote) {
2797 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2798 fdsend(ast_consock, buf);
2799 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2800 return (char*)(CC_ERROR);
2803 nummatches = atoi(buf);
2805 if (nummatches > 0) {
2807 int mlen = 0, maxmbuf = 2048;
2808 /* Start with a 2048 byte buffer */
2809 if (!(mbuf = ast_malloc(maxmbuf))) {
2810 *((char *) lf->cursor) = savechr;
2811 return (char *)(CC_ERROR);
2813 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2814 fdsend(ast_consock, buf);
2817 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2818 if (mlen + 1024 > maxmbuf) {
2819 /* Every step increment buffer 1024 bytes */
2821 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2822 *((char *) lf->cursor) = savechr;
2823 return (char *)(CC_ERROR);
2826 /* Only read 1024 bytes at a time */
2827 res = read(ast_consock, mbuf + mlen, 1024);
2833 matches = ast_el_strtoarr(mbuf);
2836 matches = (char **) NULL;
2838 char **p, *oldbuf=NULL;
2840 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2841 for (p = matches; p && *p; p++) {
2842 if (!oldbuf || strcmp(*p,oldbuf))
2850 int matches_num, maxlen, match_len;
2852 if (matches[0][0] != '\0') {
2853 el_deletestr(editline, (int) len);
2854 el_insertstr(editline, matches[0]);
2855 retval = CC_REFRESH;
2858 if (nummatches == 1) {
2859 /* Found an exact match */
2860 el_insertstr(editline, " ");
2861 retval = CC_REFRESH;
2863 /* Must be more than one match */
2864 for (i = 1, maxlen = 0; matches[i]; i++) {
2865 match_len = strlen(matches[i]);
2866 if (match_len > maxlen)
2869 matches_num = i - 1;
2870 if (matches_num >1) {
2871 fprintf(stdout, "\n");
2872 ast_cli_display_match_list(matches, nummatches, maxlen);
2873 retval = CC_REDISPLAY;
2875 el_insertstr(editline," ");
2876 retval = CC_REFRESH;
2879 for (i = 0; matches[i]; i++)
2880 ast_free(matches[i]);
2884 *((char *) lf->cursor) = savechr;
2886 return (char *)(long)retval;
2889 static int ast_el_initialize(void)
2892 char *editor, *editrc = getenv("EDITRC");
2894 if (!(editor = getenv("AST_EDITMODE"))) {
2895 if (!(editor = getenv("AST_EDITOR"))) {
2902 if (el_hist != NULL)
2903 history_end(el_hist);
2905 el = el_init("asterisk", stdin, stdout, stderr);
2906 el_set(el, EL_PROMPT, cli_prompt);
2908 el_set(el, EL_EDITMODE, 1);
2909 el_set(el, EL_EDITOR, editor);
2910 el_hist = history_init();
2911 if (!el || !el_hist)
2914 /* setup history with 100 entries */
2915 history(el_hist, &ev, H_SETSIZE, 100);
2917 el_set(el, EL_HIST, history, el_hist);
2919 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2920 /* Bind <tab> to command completion */
2921 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2922 /* Bind ? to command completion */
2923 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2924 /* Bind ^D to redisplay */
2925 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2926 /* Bind Delete to delete char left */
2927 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
2928 /* Bind Home and End to move to line start and end */
2929 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
2930 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
2931 /* Bind C-left and C-right to move by word (not all terminals) */
2932 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
2933 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
2936 el_source(el, editrc);
2942 #define MAX_HISTORY_COMMAND_LENGTH 256
2944 static int ast_el_add_history(char *buf)
2948 if (el_hist == NULL || el == NULL)
2949 ast_el_initialize();
2950 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2952 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2955 static int ast_el_write_history(char *filename)
2959 if (el_hist == NULL || el == NULL)
2960 ast_el_initialize();
2962 return (history(el_hist, &ev, H_SAVE, filename));
2965 static int ast_el_read_history(char *filename)
2969 if (el_hist == NULL || el == NULL) {
2970 ast_el_initialize();
2973 return history(el_hist, &ev, H_LOAD, filename);
2976 static void ast_remotecontrol(char *data)
2980 char filename[80] = "";
2985 char *stringp = NULL;
2990 memset(&sig_flags, 0, sizeof(sig_flags));
2991 signal(SIGINT, __remote_quit_handler);
2992 signal(SIGTERM, __remote_quit_handler);
2993 signal(SIGHUP, __remote_quit_handler);
2995 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2996 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3000 char prefix[] = "cli quit after ";
3001 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3002 sprintf(tmp, "%s%s", prefix, data);
3003 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3004 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3005 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3011 hostname = strsep(&stringp, "/");
3012 cpid = strsep(&stringp, "/");
3013 version = strsep(&stringp, "\n");
3015 version = "<Version Unknown>";
3017 strsep(&stringp, ".");
3023 if (!ast_opt_mute) {
3024 fdsend(ast_consock, "logger mute silent");
3026 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3030 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
3031 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3033 fds.fd = ast_consock;
3034 fds.events = POLLIN;
3037 while (ast_poll(&fds, 1, 60000) > 0) {
3038 char buffer[512] = "", *curline = buffer, *nextline;
3039 int not_written = 1;
3041 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3045 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3050 prev_linefull = linefull;
3051 if ((nextline = strchr(curline, '\n'))) {
3056 nextline = strchr(curline, '\0');
3059 /* Skip verbose lines */
3060 /* Prev line full? | Line is verbose | Last line verbose? | Print
3061 * TRUE | TRUE* | TRUE | FALSE
3062 * TRUE | TRUE* | FALSE | FALSE
3063 * TRUE | FALSE* | TRUE | TRUE
3064 * TRUE | FALSE* | FALSE | TRUE
3065 * FALSE | TRUE | TRUE* | FALSE
3066 * FALSE | TRUE | FALSE* | TRUE
3067 * FALSE | FALSE | TRUE* | FALSE
3068 * FALSE | FALSE | FALSE* | TRUE
3070 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3071 prev_line_verbose = 0;
3073 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3074 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3077 prev_line_verbose = 1;
3080 } while (!ast_strlen_zero(curline));
3082 /* No non-verbose output in 60 seconds. */
3090 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3091 remotehostname = hostname;
3093 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3094 if (el_hist == NULL || el == NULL)
3095 ast_el_initialize();
3097 el_set(el, EL_GETCFN, ast_el_read_char);
3099 if (!ast_strlen_zero(filename))
3100 ast_el_read_history(filename);
3103 ebuf = (char *)el_gets(el, &num);
3105 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3109 if (!ebuf && write(1, "", 1) < 0)
3112 if (!ast_strlen_zero(ebuf)) {
3113 if (ebuf[strlen(ebuf)-1] == '\n')
3114 ebuf[strlen(ebuf)-1] = '\0';
3115 if (!remoteconsolehandler(ebuf)) {
3116 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3118 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3124 printf("\nDisconnected from Asterisk server\n");
3127 static int show_version(void)
3129 printf("Asterisk %s\n", ast_get_version());
3133 static int show_cli_help(void)
3135 printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3136 printf("Usage: asterisk [OPTIONS]\n");
3137 printf("Valid Options:\n");
3138 printf(" -V Display version number and exit\n");
3139 printf(" -C <configfile> Use an alternate configuration file\n");
3140 printf(" -G <group> Run as a group other than the caller\n");
3141 printf(" -U <user> Run as a user other than the caller\n");
3142 printf(" -c Provide console CLI\n");
3143 printf(" -d Enable extra debugging\n");
3144 #if HAVE_WORKING_FORK
3145 printf(" -f Do not fork\n");
3146 printf(" -F Always fork\n");
3148 printf(" -g Dump core in case of a crash\n");
3149 printf(" -h This help screen\n");
3150 printf(" -i Initialize crypto keys at startup\n");
3151 printf(" -I Enable internal timing if DAHDI timer is available\n");
3152 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
3153 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
3154 printf(" -m Mute debugging and console output on the console\n");
3155 printf(" -n Disable console colorization\n");
3156 printf(" -p Run as pseudo-realtime thread\n");
3157 printf(" -q Quiet mode (suppress output)\n");
3158 printf(" -r Connect to Asterisk on this machine\n");
3159 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
3160 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
3161 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
3162 printf(" belong after they are done\n");
3163 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3164 printf(" of output to the CLI\n");
3165 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
3166 printf(" -x <cmd> Execute command <cmd> (implies -r)\n");
3167 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
3168 printf(" -W Adjust terminal colors to compensate for a light background\n");