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 int active_channels;
1852 if (niceness >= SHUTDOWN_NICE) {
1853 ast_module_shutdown();
1856 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1857 char filename[80] = "";
1858 if (getenv("HOME")) {
1859 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1861 if (!ast_strlen_zero(filename)) {
1862 ast_el_write_history(filename);
1864 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1865 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1869 if (el_hist != NULL) {
1870 history_end(el_hist);
1872 } else if (mon_sig_flags == pthread_self()) {
1873 if (consolethread != AST_PTHREADT_NULL) {
1874 pthread_kill(consolethread, SIGURG);
1878 active_channels = ast_active_channels();
1879 /* The manager event for shutdown must happen prior to ast_run_atexits, as
1880 * the manager interface will dispose of its sessions as part of its
1884 <managerEventInstance>
1885 <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
1887 <parameter name="Shutdown">
1889 <enum name="Uncleanly"/>
1890 <enum name="Cleanly"/>
1893 <parameter name="Restart">
1896 <enum name="False"/>
1900 </managerEventInstance>
1902 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\n"
1904 active_channels ? "Uncleanly" : "Cleanly",
1905 restart ? "True" : "False");
1907 ast_verb(0, "Executing last minute cleanups\n");
1909 /* Called on exit */
1910 ast_verb(0, "Asterisk %s ending (%d).\n", active_channels ? "uncleanly" : "cleanly", num);
1911 ast_debug(1, "Asterisk ending (%d).\n", num);
1912 if (ast_socket > -1) {
1913 pthread_cancel(lthread);
1916 unlink(ast_config_AST_SOCKET);
1918 if (ast_consock > -1)
1920 if (!ast_opt_remote)
1921 unlink(ast_config_AST_PID);
1922 printf("%s", term_quit());
1925 ast_verb(0, "Preparing for Asterisk restart...\n");
1926 /* Mark all FD's for closing on exec */
1927 for (i = 3; i < 32768; i++) {
1928 fcntl(i, F_SETFD, FD_CLOEXEC);
1930 ast_verb(0, "Asterisk is now restarting...\n");
1937 /* If there is a consolethread running send it a SIGHUP
1938 so it can execvp, otherwise we can do it ourselves */
1939 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1940 pthread_kill(consolethread, SIGHUP);
1941 /* Give the signal handler some time to complete */
1944 execvp(_argv[0], _argv);
1955 static void __quit_handler(int num)
1958 sig_flags.need_quit = 1;
1959 if (sig_alert_pipe[1] != -1) {
1960 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1961 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1964 /* There is no need to restore the signal handler here, since the app
1965 * is going to exit */
1968 static void __remote_quit_handler(int num)
1970 sig_flags.need_quit = 1;
1973 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1977 if (!strncmp(s, cmp, strlen(cmp))) {
1978 c = s + strlen(cmp);
1979 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1985 /* These gymnastics are due to platforms which designate char as unsigned by
1986 * default. Level is the negative character -- offset by 1, because \0 is the
1988 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
1989 #define VERBOSE_HASMAGIC(x) (*(signed char *) (x) < 0)
1991 static void console_verboser(const char *s)
1994 const char *c = NULL;
1997 if (VERBOSE_HASMAGIC(s)) {
1998 level = VERBOSE_MAGIC2LEVEL(s);
2000 if (level > option_verbose) {
2005 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
2006 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
2007 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
2008 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
2017 /* Wake up a poll()ing console */
2018 if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2019 pthread_kill(consolethread, SIGURG);
2023 static int ast_all_zeros(char *s)
2033 static void consolehandler(char *s)
2035 printf("%s", term_end());
2038 /* Called when readline data is available */
2039 if (!ast_all_zeros(s))
2040 ast_el_add_history(s);
2041 /* The real handler for bang */
2044 ast_safe_system(s+1);
2046 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2048 ast_cli_command(STDOUT_FILENO, s);
2051 static int remoteconsolehandler(char *s)
2055 /* Called when readline data is available */
2056 if (!ast_all_zeros(s))
2057 ast_el_add_history(s);
2058 /* The real handler for bang */
2061 ast_safe_system(s+1);
2063 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2065 } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2066 int old_verbose = option_verbose;
2067 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2069 if (sscanf(s + 25, "%d", &tmp) != 1) {
2070 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2072 if (tmp > option_verbose) {
2073 option_verbose = tmp;
2075 if (old_verbose != option_verbose) {
2076 fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2078 fprintf(stdout, "Verbosity level unchanged.\n");
2082 if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2083 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2085 if (old_verbose != option_verbose) {
2086 fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2088 fprintf(stdout, "Verbosity level unchanged.\n");
2093 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2094 (s[4] == '\0' || isspace(s[4]))) {
2095 quit_handler(0, SHUTDOWN_FAST, 0);
2102 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2106 e->command = "core show version";
2108 "Usage: core show version\n"
2109 " Shows Asterisk version information.\n";
2116 return CLI_SHOWUSAGE;
2117 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2118 ast_get_version(), ast_build_user, ast_build_hostname,
2119 ast_build_machine, ast_build_os, ast_build_date);
2124 static int handle_quit(int fd, int argc, char *argv[])
2127 return RESULT_SHOWUSAGE;
2128 quit_handler(0, SHUTDOWN_NORMAL, 0);
2129 return RESULT_SUCCESS;
2133 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2137 e->command = "core stop now";
2139 "Usage: core stop now\n"
2140 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2146 if (a->argc != e->args)
2147 return CLI_SHOWUSAGE;
2148 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2152 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2156 e->command = "core stop gracefully";
2158 "Usage: core stop gracefully\n"
2159 " Causes Asterisk to not accept new calls, and exit when all\n"
2160 " active calls have terminated normally.\n";
2166 if (a->argc != e->args)
2167 return CLI_SHOWUSAGE;
2168 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2172 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2176 e->command = "core stop when convenient";
2178 "Usage: core stop when convenient\n"
2179 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2185 if (a->argc != e->args)
2186 return CLI_SHOWUSAGE;
2187 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2188 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2192 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2196 e->command = "core restart now";
2198 "Usage: core restart now\n"
2199 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2206 if (a->argc != e->args)
2207 return CLI_SHOWUSAGE;
2208 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2212 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2216 e->command = "core restart gracefully";
2218 "Usage: core restart gracefully\n"
2219 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2220 " restart when all active calls have ended.\n";
2226 if (a->argc != e->args)
2227 return CLI_SHOWUSAGE;
2228 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2232 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2236 e->command = "core restart when convenient";
2238 "Usage: core restart when convenient\n"
2239 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2245 if (a->argc != e->args)
2246 return CLI_SHOWUSAGE;
2247 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2248 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2252 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2254 int aborting_shutdown = 0;
2258 e->command = "core abort shutdown";
2260 "Usage: core abort shutdown\n"
2261 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2262 " call operations.\n";
2268 if (a->argc != e->args)
2269 return CLI_SHOWUSAGE;
2271 ast_mutex_lock(&safe_system_lock);
2272 if (shuttingdown >= SHUTDOWN_FAST) {
2273 aborting_shutdown = 1;
2274 shuttingdown = NOT_SHUTTING_DOWN;
2276 ast_mutex_unlock(&safe_system_lock);
2278 if (aborting_shutdown) {
2279 ast_cancel_shutdown();
2284 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2290 "Usage: !<command>\n"
2291 " Executes a given shell command\n";
2299 static const char warranty_lines[] = {
2303 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2304 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2305 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2306 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2307 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2308 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2309 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2310 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2311 "REPAIR OR CORRECTION.\n"
2313 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2314 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2315 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2316 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2317 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2318 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2319 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2320 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2321 "POSSIBILITY OF SUCH DAMAGES.\n"
2324 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2328 e->command = "core show warranty";
2330 "Usage: core show warranty\n"
2331 " Shows the warranty (if any) for this copy of Asterisk.\n";
2337 ast_cli(a->fd, "%s", warranty_lines);
2342 static const char license_lines[] = {
2344 "This program is free software; you can redistribute it and/or modify\n"
2345 "it under the terms of the GNU General Public License version 2 as\n"
2346 "published by the Free Software Foundation.\n"
2348 "This program also contains components licensed under other licenses.\n"
2351 "This program is distributed in the hope that it will be useful,\n"
2352 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2353 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2354 "GNU General Public License for more details.\n"
2356 "You should have received a copy of the GNU General Public License\n"
2357 "along with this program; if not, write to the Free Software\n"
2358 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2361 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2365 e->command = "core show license";
2367 "Usage: core show license\n"
2368 " Shows the license(s) for this copy of Asterisk.\n";
2374 ast_cli(a->fd, "%s", license_lines);
2379 #define ASTERISK_PROMPT "*CLI> "
2381 #define ASTERISK_PROMPT2 "%s*CLI> "
2384 * \brief Shutdown Asterisk CLI commands.
2386 * \note These CLI commands cannot be unregistered at shutdown
2387 * because one of them is likely the reason for the shutdown.
2388 * The CLI generates a warning if a command is in-use when it is
2391 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2392 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2393 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2394 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2395 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2396 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2397 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2400 static struct ast_cli_entry cli_asterisk[] = {
2401 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2402 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2403 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2404 AST_CLI_DEFINE(handle_version, "Display version info"),
2405 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2406 #if !defined(LOW_MEMORY)
2407 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2408 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2409 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2410 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2412 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2413 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2414 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2415 #endif /* ! LOW_MEMORY */
2418 struct el_read_char_state_struct {
2419 unsigned int line_full:1;
2420 unsigned int prev_line_full:1;
2421 char prev_line_verbosity;
2424 static int el_read_char_state_init(void *ptr)
2426 struct el_read_char_state_struct *state = ptr;
2427 state->line_full = 1;
2428 state->prev_line_full = 1;
2429 state->prev_line_verbosity = 0;
2433 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2435 static int ast_el_read_char(EditLine *editline, char *cp)
2439 struct pollfd fds[2];
2442 #define EL_BUF_SIZE 512
2443 char buf[EL_BUF_SIZE];
2444 struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2448 fds[0].fd = ast_consock;
2449 fds[0].events = POLLIN;
2450 if (!ast_opt_exec) {
2451 fds[1].fd = STDIN_FILENO;
2452 fds[1].events = POLLIN;
2455 res = ast_poll(fds, max, -1);
2457 if (sig_flags.need_quit || sig_flags.need_quit_handler)
2461 fprintf(stderr, "poll failed: %s\n", strerror(errno));
2465 if (!ast_opt_exec && fds[1].revents) {
2466 num_read = read(STDIN_FILENO, cp, 1);
2473 if (fds[0].revents) {
2475 char *curline = buf, *nextline;
2476 res = read(ast_consock, buf, sizeof(buf) - 1);
2477 /* if the remote side disappears exit */
2479 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2480 if (!ast_opt_reconnect) {
2481 quit_handler(0, SHUTDOWN_FAST, 0);
2484 int reconnects_per_second = 20;
2485 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2486 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2487 if (ast_tryconnect()) {
2488 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2489 printf("%s", term_quit());
2492 fdsend(ast_consock, "logger mute silent");
2494 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2497 usleep(1000000 / reconnects_per_second);
2499 if (tries >= 30 * reconnects_per_second) {
2500 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2501 quit_handler(0, SHUTDOWN_FAST, 0);
2509 /* Write over the CLI prompt */
2510 if (!ast_opt_exec && !lastpos) {
2511 if (write(STDOUT_FILENO, "\r
\e[0K", 5) < 0) {
2516 state->prev_line_full = state->line_full;
2517 if ((nextline = strchr(curline, '\n'))) {
2518 state->line_full = 1;
2521 state->line_full = 0;
2522 nextline = strchr(curline, '\0');
2525 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2526 level = VERBOSE_MAGIC2LEVEL(curline);
2528 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2529 /* Non-verbose output */
2532 level = state->prev_line_verbosity;
2534 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2535 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2539 state->prev_line_verbosity = level;
2541 } while (!ast_strlen_zero(curline));
2543 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2555 static struct ast_str *prompt = NULL;
2557 static char *cli_prompt(EditLine *editline)
2562 static int cli_prompt_changes = 0;
2567 if (prompt == NULL) {
2568 prompt = ast_str_create(100);
2569 } else if (!cli_prompt_changes) {
2570 return ast_str_buffer(prompt);
2572 ast_str_reset(prompt);
2575 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2577 struct timeval ts = ast_tvnow();
2578 while (*t != '\0') {
2580 char hostname[MAXHOSTNAMELEN] = "";
2582 struct ast_tm tm = { 0, };
2583 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2587 case 'C': /* color */
2589 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2590 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2592 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2593 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2597 /* If the color has been reset correctly, then there's no need to reset it later */
2598 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2600 case 'd': /* date */
2601 if (ast_localtime(&ts, &tm, NULL)) {
2602 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2603 ast_str_append(&prompt, 0, "%s", tmp);
2604 cli_prompt_changes++;
2607 case 'g': /* group */
2608 if ((gr = getgrgid(getgid()))) {
2609 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2612 case 'h': /* hostname */
2613 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2614 ast_str_append(&prompt, 0, "%s", hostname);
2616 ast_str_append(&prompt, 0, "%s", "localhost");
2619 case 'H': /* short hostname */
2620 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2622 if ((dotptr = strchr(hostname, '.'))) {
2625 ast_str_append(&prompt, 0, "%s", hostname);
2627 ast_str_append(&prompt, 0, "%s", "localhost");
2630 #ifdef HAVE_GETLOADAVG
2631 case 'l': /* load avg */
2633 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2635 getloadavg(list, 3);
2636 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2637 cli_prompt_changes++;
2641 case 's': /* Asterisk system name (from asterisk.conf) */
2642 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2644 case 't': /* time */
2645 if (ast_localtime(&ts, &tm, NULL)) {
2646 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2647 ast_str_append(&prompt, 0, "%s", tmp);
2648 cli_prompt_changes++;
2651 case 'u': /* username */
2652 if ((pw = getpwuid(getuid()))) {
2653 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2656 case '#': /* process console or remote? */
2657 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2659 case '%': /* literal % */
2660 ast_str_append(&prompt, 0, "%c", '%');
2662 case '\0': /* % is last character - prevent bug */
2667 ast_str_append(&prompt, 0, "%c", *t);
2672 /* Force colors back to normal at end */
2673 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2675 } else if (remotehostname) {
2676 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2678 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2681 return ast_str_buffer(prompt);
2684 static char **ast_el_strtoarr(char *buf)
2686 char **match_list = NULL, **match_list_tmp, *retstr;
2687 size_t match_list_len;
2691 while ( (retstr = strsep(&buf, " ")) != NULL) {
2693 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2695 if (matches + 1 >= match_list_len) {
2696 match_list_len <<= 1;
2697 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2698 match_list = match_list_tmp;
2701 ast_free(match_list);
2702 return (char **) NULL;
2706 match_list[matches++] = ast_strdup(retstr);
2710 return (char **) NULL;
2712 if (matches >= match_list_len) {
2713 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2714 match_list = match_list_tmp;
2717 ast_free(match_list);
2718 return (char **) NULL;
2722 match_list[matches] = (char *) NULL;
2727 static int ast_el_sort_compare(const void *i1, const void *i2)
2731 s1 = ((char **)i1)[0];
2732 s2 = ((char **)i2)[0];
2734 return strcasecmp(s1, s2);
2737 static int ast_cli_display_match_list(char **matches, int len, int max)
2739 int i, idx, limit, count;
2740 int screenwidth = 0;
2741 int numoutput = 0, numoutputline = 0;
2743 screenwidth = ast_get_termcols(STDOUT_FILENO);
2745 /* find out how many entries can be put on one line, with two spaces between strings */
2746 limit = screenwidth / (max + 2);
2750 /* how many lines of output */
2751 count = len / limit;
2752 if (count * limit < len)
2757 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2759 for (; count > 0; count--) {
2761 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2763 /* Don't print dupes */
2764 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2766 ast_free(matches[idx]);
2767 matches[idx] = NULL;
2773 fprintf(stdout, "%-*s ", max, matches[idx]);
2774 ast_free(matches[idx]);
2775 matches[idx] = NULL;
2777 if (numoutputline > 0)
2778 fprintf(stdout, "\n");
2785 static char *cli_complete(EditLine *editline, int ch)
2791 int retval = CC_ERROR;
2792 char buf[2048], savechr;
2795 LineInfo *lf = (LineInfo *)el_line(editline);
2797 savechr = *(char *)lf->cursor;
2798 *(char *)lf->cursor = '\0';
2799 ptr = (char *)lf->cursor;
2801 while (ptr > lf->buffer) {
2802 if (isspace(*ptr)) {
2810 len = lf->cursor - ptr;
2812 if (ast_opt_remote) {
2813 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2814 fdsend(ast_consock, buf);
2815 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2816 return (char*)(CC_ERROR);
2819 nummatches = atoi(buf);
2821 if (nummatches > 0) {
2823 int mlen = 0, maxmbuf = 2048;
2824 /* Start with a 2048 byte buffer */
2825 if (!(mbuf = ast_malloc(maxmbuf))) {
2826 *((char *) lf->cursor) = savechr;
2827 return (char *)(CC_ERROR);
2829 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2830 fdsend(ast_consock, buf);
2833 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2834 if (mlen + 1024 > maxmbuf) {
2835 /* Every step increment buffer 1024 bytes */
2837 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2838 *((char *) lf->cursor) = savechr;
2839 return (char *)(CC_ERROR);
2842 /* Only read 1024 bytes at a time */
2843 res = read(ast_consock, mbuf + mlen, 1024);
2849 matches = ast_el_strtoarr(mbuf);
2852 matches = (char **) NULL;
2854 char **p, *oldbuf=NULL;
2856 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2857 for (p = matches; p && *p; p++) {
2858 if (!oldbuf || strcmp(*p,oldbuf))
2866 int matches_num, maxlen, match_len;
2868 if (matches[0][0] != '\0') {
2869 el_deletestr(editline, (int) len);
2870 el_insertstr(editline, matches[0]);
2871 retval = CC_REFRESH;
2874 if (nummatches == 1) {
2875 /* Found an exact match */
2876 el_insertstr(editline, " ");
2877 retval = CC_REFRESH;
2879 /* Must be more than one match */
2880 for (i = 1, maxlen = 0; matches[i]; i++) {
2881 match_len = strlen(matches[i]);
2882 if (match_len > maxlen)
2885 matches_num = i - 1;
2886 if (matches_num >1) {
2887 fprintf(stdout, "\n");
2888 ast_cli_display_match_list(matches, nummatches, maxlen);
2889 retval = CC_REDISPLAY;
2891 el_insertstr(editline," ");
2892 retval = CC_REFRESH;
2895 for (i = 0; matches[i]; i++)
2896 ast_free(matches[i]);
2900 *((char *) lf->cursor) = savechr;
2902 return (char *)(long)retval;
2905 static int ast_el_initialize(void)
2908 char *editor, *editrc = getenv("EDITRC");
2910 if (!(editor = getenv("AST_EDITMODE"))) {
2911 if (!(editor = getenv("AST_EDITOR"))) {
2918 if (el_hist != NULL)
2919 history_end(el_hist);
2921 el = el_init("asterisk", stdin, stdout, stderr);
2922 el_set(el, EL_PROMPT, cli_prompt);
2924 el_set(el, EL_EDITMODE, 1);
2925 el_set(el, EL_EDITOR, editor);
2926 el_hist = history_init();
2927 if (!el || !el_hist)
2930 /* setup history with 100 entries */
2931 history(el_hist, &ev, H_SETSIZE, 100);
2933 el_set(el, EL_HIST, history, el_hist);
2935 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2936 /* Bind <tab> to command completion */
2937 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2938 /* Bind ? to command completion */
2939 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2940 /* Bind ^D to redisplay */
2941 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2942 /* Bind Delete to delete char left */
2943 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
2944 /* Bind Home and End to move to line start and end */
2945 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
2946 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
2947 /* Bind C-left and C-right to move by word (not all terminals) */
2948 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
2949 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
2952 el_source(el, editrc);
2958 #define MAX_HISTORY_COMMAND_LENGTH 256
2960 static int ast_el_add_history(char *buf)
2964 if (el_hist == NULL || el == NULL)
2965 ast_el_initialize();
2966 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2968 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2971 static int ast_el_write_history(char *filename)
2975 if (el_hist == NULL || el == NULL)
2976 ast_el_initialize();
2978 return (history(el_hist, &ev, H_SAVE, filename));
2981 static int ast_el_read_history(char *filename)
2985 if (el_hist == NULL || el == NULL) {
2986 ast_el_initialize();
2989 return history(el_hist, &ev, H_LOAD, filename);
2992 static void ast_remotecontrol(char *data)
2996 char filename[80] = "";
3001 char *stringp = NULL;
3006 memset(&sig_flags, 0, sizeof(sig_flags));
3007 signal(SIGINT, __remote_quit_handler);
3008 signal(SIGTERM, __remote_quit_handler);
3009 signal(SIGHUP, __remote_quit_handler);
3011 if (read(ast_consock, buf, sizeof(buf)) < 0) {
3012 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3016 char prefix[] = "cli quit after ";
3017 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3018 sprintf(tmp, "%s%s", prefix, data);
3019 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3020 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3021 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3027 hostname = strsep(&stringp, "/");
3028 cpid = strsep(&stringp, "/");
3029 version = strsep(&stringp, "\n");
3031 version = "<Version Unknown>";
3033 strsep(&stringp, ".");
3039 if (!ast_opt_mute) {
3040 fdsend(ast_consock, "logger mute silent");
3042 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3046 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
3047 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3049 fds.fd = ast_consock;
3050 fds.events = POLLIN;
3053 while (ast_poll(&fds, 1, 60000) > 0) {
3054 char buffer[512] = "", *curline = buffer, *nextline;
3055 int not_written = 1;
3057 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3061 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3066 prev_linefull = linefull;
3067 if ((nextline = strchr(curline, '\n'))) {
3072 nextline = strchr(curline, '\0');
3075 /* Skip verbose lines */
3076 /* Prev line full? | Line is verbose | Last line verbose? | Print
3077 * TRUE | TRUE* | TRUE | FALSE
3078 * TRUE | TRUE* | FALSE | FALSE
3079 * TRUE | FALSE* | TRUE | TRUE
3080 * TRUE | FALSE* | FALSE | TRUE
3081 * FALSE | TRUE | TRUE* | FALSE
3082 * FALSE | TRUE | FALSE* | TRUE
3083 * FALSE | FALSE | TRUE* | FALSE
3084 * FALSE | FALSE | FALSE* | TRUE
3086 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3087 prev_line_verbose = 0;
3089 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3090 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3093 prev_line_verbose = 1;
3096 } while (!ast_strlen_zero(curline));
3098 /* No non-verbose output in 60 seconds. */
3106 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3107 remotehostname = hostname;
3109 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3110 if (el_hist == NULL || el == NULL)
3111 ast_el_initialize();
3113 el_set(el, EL_GETCFN, ast_el_read_char);
3115 if (!ast_strlen_zero(filename))
3116 ast_el_read_history(filename);
3119 ebuf = (char *)el_gets(el, &num);
3121 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3125 if (!ebuf && write(1, "", 1) < 0)
3128 if (!ast_strlen_zero(ebuf)) {
3129 if (ebuf[strlen(ebuf)-1] == '\n')
3130 ebuf[strlen(ebuf)-1] = '\0';
3131 if (!remoteconsolehandler(ebuf)) {
3132 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3134 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3140 printf("\nDisconnected from Asterisk server\n");
3143 static int show_version(void)
3145 printf("Asterisk %s\n", ast_get_version());
3149 static int show_cli_help(void)
3151 printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3152 printf("Usage: asterisk [OPTIONS]\n");
3153 printf("Valid Options:\n");
3154 printf(" -V Display version number and exit\n");
3155 printf(" -C <configfile> Use an alternate configuration file\n");
3156 printf(" -G <group> Run as a group other than the caller\n");
3157 printf(" -U <user> Run as a user other than the caller\n");
3158 printf(" -c Provide console CLI\n");
3159 printf(" -d Enable extra debugging\n");
3160 #if HAVE_WORKING_FORK
3161 printf(" -f Do not fork\n");
3162 printf(" -F Always fork\n");
3164 printf(" -g Dump core in case of a crash\n");
3165 printf(" -h This help screen\n");
3166 printf(" -i Initialize crypto keys at startup\n");
3167 printf(" -I Enable internal timing if DAHDI timer is available\n");
3168 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
3169 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
3170 printf(" -m Mute debugging and console output on the console\n");
3171 printf(" -n Disable console colorization\n");
3172 printf(" -p Run as pseudo-realtime thread\n");
3173 printf(" -q Quiet mode (suppress output)\n");
3174 printf(" -r Connect to Asterisk on this machine\n");
3175 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
3176 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
3177 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
3178 printf(" belong after they are done\n");
3179 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3180 printf(" of output to the CLI\n");
3181 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
3182 printf(" -x <cmd> Execute command <cmd> (implies -r)\n");
3183 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
3184 printf(" -W Adjust terminal colors to compensate for a light background\n");
3189 static void ast_readconfig(void)
3191 struct ast_config *cfg;
3192 struct ast_variable *v;
3193 char *config = DEFAULT_CONFIG_FILE;
3194 char hostname[MAXHOSTNAMELEN] = "";
3195 struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3197 unsigned int dbdir:1;
3198 unsigned int keydir:1;
3201 /* Set default value */
3202 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3204 if (ast_opt_override_config) {
3205 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3206 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3207 fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3210 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3213 /* init with buildtime config */
3214 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3215 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3216 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3217 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3218 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3219 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3220 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3221 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3222 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3223 ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3224 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3225 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3226 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3227 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3229 ast_set_default_eid(&ast_eid_default);
3231 /* no asterisk.conf? no problem, use buildtime config! */
3232 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3236 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3237 if (!strcasecmp(v->name, "astctlpermissions"))
3238 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3239 else if (!strcasecmp(v->name, "astctlowner"))
3240 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3241 else if (!strcasecmp(v->name, "astctlgroup"))
3242 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3243 else if (!strcasecmp(v->name, "astctl"))
3244 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3247 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3248 if (!strcasecmp(v->name, "astetcdir")) {
3249 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3250 } else if (!strcasecmp(v->name, "astspooldir")) {
3251 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3252 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3253 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3254 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3256 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3257 } else if (!strcasecmp(v->name, "astdbdir")) {
3258 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3260 } else if (!strcasecmp(v->name, "astdatadir")) {
3261 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3263 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3264 } else if (!strcasecmp(v->name, "astkeydir")) {
3265 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3267 } else if (!strcasecmp(v->name, "astlogdir")) {
3268 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3269 } else if (!strcasecmp(v->name, "astagidir")) {
3270 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3271 } else if (!strcasecmp(v->name, "astrundir")) {
3272 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3273 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3274 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3275 } else if (!strcasecmp(v->name, "astmoddir")) {
3276 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3277 } else if (!strcasecmp(v->name, "astsbindir")) {
3278 ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3282 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3283 /* verbose level (-v at startup) */
3284 if (!strcasecmp(v->name, "verbose")) {
3285 option_verbose = atoi(v->value);
3286 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3287 } else if (!strcasecmp(v->name, "timestamp")) {
3288 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3289 /* whether or not to support #exec in config files */
3290 } else if (!strcasecmp(v->name, "execincludes")) {
3291 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3292 /* debug level (-d at startup) */
3293 } else if (!strcasecmp(v->name, "debug")) {
3295 if (sscanf(v->value, "%30d", &option_debug) != 1) {
3296 option_debug = ast_true(v->value);
3298 #if HAVE_WORKING_FORK
3299 /* Disable forking (-f at startup) */
3300 } else if (!strcasecmp(v->name, "nofork")) {
3301 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3302 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3303 } else if (!strcasecmp(v->name, "alwaysfork")) {
3304 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3306 /* Run quietly (-q at startup ) */
3307 } else if (!strcasecmp(v->name, "quiet")) {
3308 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3309 /* Run as console (-c at startup, implies nofork) */
3310 } else if (!strcasecmp(v->name, "console")) {
3311 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3312 /* Run with high priority if the O/S permits (-p at startup) */
3313 } else if (!strcasecmp(v->name, "highpriority")) {
3314 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3315 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3316 } else if (!strcasecmp(v->name, "initcrypto")) {
3317 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3318 /* Disable ANSI colors for console (-c at startup) */
3319 } else if (!strcasecmp(v->name, "nocolor")) {
3320 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3321 /* Disable some usage warnings for picky people :p */
3322 } else if (!strcasecmp(v->name, "dontwarn")) {
3323 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3324 /* Dump core in case of crash (-g) */
3325 } else if (!strcasecmp(v->name, "dumpcore")) {
3326 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3327 /* Cache recorded sound files to another directory during recording */
3328 } else if (!strcasecmp(v->name, "cache_record_files")) {
3329 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3330 /* Specify cache directory */
3331 } else if (!strcasecmp(v->name, "record_cache_dir")) {
3332 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3333 /* Build transcode paths via SLINEAR, instead of directly */
3334 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3335 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3336 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3337 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3338 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3339 /* Enable internal timing */
3340 } else if (!strcasecmp(v->name, "internal_timing")) {
3341 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
3342 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3343 if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3344 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3346 } else if (!strcasecmp(v->name, "maxcalls")) {
3347 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3348 option_maxcalls = 0;
3350 } else if (!strcasecmp(v->name, "maxload")) {
3353 if (getloadavg(test, 1) == -1) {
3354 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3355 option_maxload = 0.0;
3356 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3357 option_maxload = 0.0;
3359 /* Set the maximum amount of open files */
3360 } else if (!strcasecmp(v->name, "maxfiles")) {
3361 option_maxfiles = atoi(v->value);
3362 set_ulimit(option_maxfiles);
3363 /* What user to run as */
3364 } else if (!strcasecmp(v->name, "runuser")) {
3365 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3366 /* What group to run as */
3367 } else if (!strcasecmp(v->name, "rungroup")) {
3368 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3369 } else if (!strcasecmp(v->name, "systemname")) {
3370 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3371 } else if (!strcasecmp(v->name, "autosystemname")) {
3372 if (ast_true(v->value)) {
3373 if (!gethostname(hostname, sizeof(hostname) - 1))
3374 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3376 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3377 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3379 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3382 } else if (!strcasecmp(v->name, "languageprefix")) {
3383 ast_language_is_prefix = ast_true(v->value);
3384 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3385 ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
3386 } else if (!strcasecmp(v->name, "lockmode")) {
3387 if (!strcasecmp(v->value, "lockfile")) {
3388 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3389 } else if (!strcasecmp(v->value, "flock")) {
3390 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3392 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3393 "defaulting to 'lockfile'\n", v->value);
3394 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3396 #if defined(HAVE_SYSINFO)
3397 } else if (!strcasecmp(v->name, "minmemfree")) {
3398 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
3399 * if the amount of free memory falls below this watermark */
3400 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3401 option_minmemfree = 0;
3404 } else if (!strcasecmp(v->name, "entityid")) {
3405 struct ast_eid tmp_eid;
3406 if (!ast_str_to_eid(&tmp_eid, v->value)) {
3407 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3408 ast_eid_default = tmp_eid;
3410 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3411 } else if (!strcasecmp(v->name, "lightbackground")) {
3412 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3413 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3414 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3415 } else if (!strcasecmp(v->name, "hideconnect")) {
3416 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3417 } else if (!strcasecmp(v->name, "lockconfdir")) {
3418 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3419 } else if (!strcasecmp(v->name, "stdexten")) {
3420 /* Choose how to invoke the extensions.conf stdexten */
3421 if (!strcasecmp(v->value, "gosub")) {
3422 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3423 } else if (!strcasecmp(v->value, "macro")) {
3424 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3426 ast_log(LOG_WARNING,
3427 "'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
3429 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3433 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3435 if (sscanf(v->value, "%30f", &version) != 1) {
3436 fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3439 if (!strcasecmp(v->name, "app_set")) {
3440 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3441 } else if (!strcasecmp(v->name, "res_agi")) {
3442 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3443 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3444 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3447 ast_config_destroy(cfg);
3450 static void *monitor_sig_flags(void *unused)
3453 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3455 ast_poll(&p, 1, -1);
3456 if (sig_flags.need_reload) {
3457 sig_flags.need_reload = 0;
3458 ast_module_reload(NULL);
3460 if (sig_flags.need_quit) {
3461 sig_flags.need_quit = 0;
3462 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3463 sig_flags.need_quit_handler = 1;
3464 pthread_kill(consolethread, SIGURG);
3466 quit_handler(0, SHUTDOWN_NORMAL, 0);
3469 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3476 static void *canary_thread(void *unused)
3478 struct stat canary_stat;
3481 /* Give the canary time to sing */
3486 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3487 ast_log(LOG_WARNING,
3488 "The canary is no more. He has ceased to be! "
3489 "He's expired and gone to meet his maker! "
3490 "He's a stiff! Bereft of life, he rests in peace. "
3491 "His metabolic processes are now history! He's off the twig! "
3492 "He's kicked the bucket. He's shuffled off his mortal coil, "
3493 "run down the curtain, and joined the bleeding choir invisible!! "
3494 "THIS is an EX-CANARY. (Reducing priority)\n");
3495 ast_set_priority(0);
3499 /* Check the canary once a minute */
3504 /* Used by libc's atexit(3) function */
3505 static void canary_exit(void)
3508 kill(canary_pid, SIGKILL);
3511 static void run_startup_commands(void)
3514 struct ast_config *cfg;
3515 struct ast_flags cfg_flags = { 0 };
3516 struct ast_variable *v;
3518 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3520 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3524 fd = open("/dev/null", O_RDWR);
3526 ast_config_destroy(cfg);
3530 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3531 if (ast_true(v->value))
3532 ast_cli_command(fd, v->name);
3536 ast_config_destroy(cfg);
3539 static void env_init(void)
3541 setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
3542 setenv("AST_BUILD_HOST", ast_build_hostname, 1);
3543 setenv("AST_BUILD_DATE", ast_build_date, 1);
3544 setenv("AST_BUILD_KERNEL", ast_build_kernel, 1);
3545 setenv("AST_BUILD_MACHINE", ast_build_machine, 1);
3546 setenv("AST_BUILD_OS", ast_build_os, 1);
3547 setenv("AST_BUILD_USER", ast_build_user, 1);
3548 setenv("AST_VERSION", ast_get_version(), 1);
3551 static void print_intro_message(const char *runuser, const char *rungroup)
3553 if (ast_opt_console || option_verbose) {
3554 if (ast_register_verbose(console_verboser)) {
3555 fprintf(stderr, "Unable to register console verboser?\n");
3560 ast_verbose("Running as user '%s'\n", runuser);
3563 ast_verbose("Running under group '%s'\n", rungroup);
3568 static void main_atexit(void)
3570 ast_cli_unregister_multiple(cli_asterisk, ARRAY_LEN(cli_asterisk));
3573 int main(int argc, char *argv[])
3576 char filename[80] = "";
3577 char hostname[MAXHOSTNAMELEN] = "";
3584 int isroot = 1, rundir_exists = 0;
3586 const char *runuser = NULL, *rungroup = NULL;
3587 char *remotesock = NULL;
3588 int moduleresult; /*!< Result from the module load subsystem */
3591 /* Remember original args for restart */
3592 if (argc > ARRAY_LEN(_argv) - 1) {
3593 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
3594 argc = ARRAY_LEN(_argv) - 1;
3596 for (x = 0; x < argc; x++)
3603 /* if the progname is rasterisk consider it a remote console */