2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2008, 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
24 * \par Developer Documentation for Asterisk
26 * This is the main developer documentation for Asterisk. It is
27 * generated by running "make progdocs" from the Asterisk source tree.
29 * In addition to the information available on the Asterisk source code,
30 * please see the appendices for information on coding guidelines,
31 * release management, commit policies, and more.
33 * \arg \ref AsteriskArchitecture
35 * \par Additional documentation
38 * \arg \ref ConfigFiles
40 * \section copyright Copyright and Author
42 * Copyright (C) 1999 - 2009, Digium, Inc.
43 * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
44 * of <a href="http://www.digium.com">Digium, Inc</a>.
46 * \author Mark Spencer <markster@digium.com>
47 * Also see \ref AstCREDITS
49 * See http://www.asterisk.org for more information about
50 * the Asterisk project. Please do not directly contact
51 * any of the maintainers of this project for assistance;
52 * the project provides a web site, mailing lists, and IRC
53 * channels for your use.
57 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
58 of PBX core functions and CLI interface.
64 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
66 #include "asterisk/_private.h"
68 #undef sched_setscheduler
77 #include <sys/resource.h>
81 #if defined(HAVE_SYSINFO)
82 #include <sys/sysinfo.h>
83 #elif defined(HAVE_SYSCTL)
84 #include <sys/param.h>
85 #include <sys/sysctl.h>
86 #if !defined(__OpenBSD__)
87 #include <sys/vmmeter.h>
88 #if defined(__FreeBSD__)
89 #include <vm/vm_param.h>
92 #if defined(HAVE_SWAPCTL)
99 int daemon(int, int); /* defined in libresolv of all places */
100 #include <sys/loadavg.h>
104 #include <sys/prctl.h>
106 #include <sys/capability.h>
107 #endif /* HAVE_CAP */
110 #include "asterisk/paths.h" /* we define here the variables so better agree on the prototype */
111 #include "asterisk/network.h"
112 #include "asterisk/cli.h"
113 #include "asterisk/channel.h"
114 #include "asterisk/features.h"
115 #include "asterisk/ulaw.h"
116 #include "asterisk/alaw.h"
117 #include "asterisk/callerid.h"
118 #include "asterisk/image.h"
119 #include "asterisk/tdd.h"
120 #include "asterisk/term.h"
121 #include "asterisk/manager.h"
122 #include "asterisk/cdr.h"
123 #include "asterisk/cel.h"
124 #include "asterisk/pbx.h"
125 #include "asterisk/enum.h"
126 #include "asterisk/http.h"
127 #include "asterisk/udptl.h"
128 #include "asterisk/app.h"
129 #include "asterisk/lock.h"
130 #include "asterisk/utils.h"
131 #include "asterisk/file.h"
132 #include "asterisk/io.h"
133 #include "editline/histedit.h"
134 #include "asterisk/config.h"
135 #include "asterisk/ast_version.h"
136 #include "asterisk/linkedlists.h"
137 #include "asterisk/devicestate.h"
138 #include "asterisk/module.h"
139 #include "asterisk/dsp.h"
140 #include "asterisk/buildinfo.h"
141 #include "asterisk/xmldoc.h"
142 #include "asterisk/poll-compat.h"
143 #include "asterisk/ccss.h"
144 #include "asterisk/test.h"
146 #include "../defaults.h"
149 #define AF_LOCAL AF_UNIX
150 #define PF_LOCAL PF_UNIX
153 #define AST_MAX_CONNECTS 128
156 /*! \brief Welcome message when starting a CLI interface */
157 #define WELCOME_MESSAGE \
158 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2010 Digium, Inc. and others.\n" \
159 "Created by Mark Spencer <markster@digium.com>\n" \
160 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
161 "This is free software, with components licensed under the GNU General Public\n" \
162 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
163 "certain conditions. Type 'core show license' for details.\n" \
164 "=========================================================================\n", ast_get_version()) \
166 /*! \defgroup main_options Main Configuration Options
167 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
168 * \arg \ref Config_ast "asterisk.conf"
169 * \note Some of them can be changed in the CLI
173 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
174 struct ast_flags ast_compat = { 0 };
176 int option_verbose; /*!< Verbosity level */
177 int option_debug; /*!< Debug level */
178 double option_maxload; /*!< Max load avg on system */
179 int option_maxcalls; /*!< Max number of active calls */
180 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
181 #if defined(HAVE_SYSINFO)
182 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
187 struct ast_eid ast_eid_default;
189 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
190 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
192 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
193 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
196 int fd; /*!< File descriptor */
197 int p[2]; /*!< Pipe */
198 pthread_t t; /*!< Thread of handler */
199 int mute; /*!< Is the console muted for logs */
200 int uid; /*!< Remote user ID. */
201 int gid; /*!< Remote group ID. */
202 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
207 AST_RWLIST_ENTRY(ast_atexit) list;
210 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
212 struct timeval ast_startuptime;
213 struct timeval ast_lastreloadtime;
215 static History *el_hist;
217 static char *remotehostname;
219 struct console consoles[AST_MAX_CONNECTS];
221 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
223 static int ast_el_add_history(char *);
224 static int ast_el_read_history(char *);
225 static int ast_el_write_history(char *);
228 char config_dir[PATH_MAX];
229 char module_dir[PATH_MAX];
230 char spool_dir[PATH_MAX];
231 char monitor_dir[PATH_MAX];
232 char var_dir[PATH_MAX];
233 char data_dir[PATH_MAX];
234 char log_dir[PATH_MAX];
235 char agi_dir[PATH_MAX];
236 char run_dir[PATH_MAX];
237 char key_dir[PATH_MAX];
239 char config_file[PATH_MAX];
240 char db_path[PATH_MAX];
241 char pid_path[PATH_MAX];
242 char socket_path[PATH_MAX];
243 char run_user[PATH_MAX];
244 char run_group[PATH_MAX];
245 char system_name[128];
248 static struct _cfg_paths cfg_paths;
250 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
251 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
252 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
253 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
254 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
255 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
256 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
257 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
258 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
259 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
260 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
262 const char *ast_config_AST_DB = cfg_paths.db_path;
263 const char *ast_config_AST_PID = cfg_paths.pid_path;
264 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
265 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
266 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
267 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
269 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
270 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
271 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
272 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
274 static char *_argv[256];
275 static int shuttingdown;
276 static int restartnow;
277 static pthread_t consolethread = AST_PTHREADT_NULL;
278 static int canary_pid = 0;
279 static char canary_filename[128];
281 static char randompool[256];
283 static int sig_alert_pipe[2] = { -1, -1 };
285 unsigned int need_reload:1;
286 unsigned int need_quit:1;
289 #if !defined(LOW_MEMORY)
290 struct file_version {
291 AST_RWLIST_ENTRY(file_version) list;
296 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
298 void ast_register_file_version(const char *file, const char *version)
300 struct file_version *new;
302 size_t version_length;
304 work = ast_strdupa(version);
305 work = ast_strip(ast_strip_quoted(work, "$", "$"));
306 version_length = strlen(work) + 1;
308 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
312 new->version = (char *) new + sizeof(*new);
313 memcpy(new->version, work, version_length);
314 AST_RWLIST_WRLOCK(&file_versions);
315 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
316 AST_RWLIST_UNLOCK(&file_versions);
319 void ast_unregister_file_version(const char *file)
321 struct file_version *find;
323 AST_RWLIST_WRLOCK(&file_versions);
324 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
325 if (!strcasecmp(find->file, file)) {
326 AST_RWLIST_REMOVE_CURRENT(list);
330 AST_RWLIST_TRAVERSE_SAFE_END;
331 AST_RWLIST_UNLOCK(&file_versions);
337 char *ast_complete_source_filename(const char *partial, int n)
339 struct file_version *find;
340 size_t len = strlen(partial);
344 AST_RWLIST_RDLOCK(&file_versions);
345 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
346 if (!strncasecmp(find->file, partial, len) && ++count > n) {
347 res = ast_strdup(find->file);
351 AST_RWLIST_UNLOCK(&file_versions);
355 /*! \brief Find version for given module name */
356 const char *ast_file_version_find(const char *file)
358 struct file_version *iterator;
360 AST_RWLIST_WRLOCK(&file_versions);
361 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, iterator, list) {
362 if (!strcasecmp(iterator->file, file))
365 AST_RWLIST_TRAVERSE_SAFE_END;
366 AST_RWLIST_UNLOCK(&file_versions);
368 return iterator->version;
374 struct thread_list_t {
375 AST_RWLIST_ENTRY(thread_list_t) list;
380 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
382 void ast_register_thread(char *name)
384 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
388 new->id = pthread_self();
389 new->name = name; /* steal the allocated memory for the thread name */
390 AST_RWLIST_WRLOCK(&thread_list);
391 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
392 AST_RWLIST_UNLOCK(&thread_list);
395 void ast_unregister_thread(void *id)
397 struct thread_list_t *x;
399 AST_RWLIST_WRLOCK(&thread_list);
400 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
401 if ((void *) x->id == id) {
402 AST_RWLIST_REMOVE_CURRENT(list);
406 AST_RWLIST_TRAVERSE_SAFE_END;
407 AST_RWLIST_UNLOCK(&thread_list);
414 /*! \brief Give an overview of core settings */
415 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
423 e->command = "core show settings";
424 e->usage = "Usage: core show settings\n"
425 " Show core misc settings";
431 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
433 ast_cli(a->fd, "\nPBX Core settings\n");
434 ast_cli(a->fd, "-----------------\n");
435 ast_cli(a->fd, " Version: %s\n", ast_get_version());
436 ast_cli(a->fd, " Build Options: %s\n", S_OR(AST_BUILDOPTS, "(none)"));
438 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
440 ast_cli(a->fd, " Maximum calls: Not set\n");
442 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
444 ast_cli(a->fd, " Maximum open file handles: Not set\n");
445 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
446 ast_cli(a->fd, " Debug level: %d\n", option_debug);
447 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
448 #if defined(HAVE_SYSINFO)
449 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
451 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
452 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
453 ast_cli(a->fd, " Startup time: %s\n", buf);
455 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
456 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
457 ast_cli(a->fd, " Last reload time: %s\n", buf);
459 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);
460 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
461 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
462 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
463 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
464 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
465 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
466 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
467 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
468 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
470 ast_cli(a->fd, "\n* Subsystems\n");
471 ast_cli(a->fd, " -------------\n");
472 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
473 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
474 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
475 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
477 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
479 ast_cli(a->fd, "\n* Directories\n");
480 ast_cli(a->fd, " -------------\n");
481 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
482 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
483 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
484 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
485 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
486 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
487 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
488 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
489 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
490 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
491 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
492 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
493 ast_cli(a->fd, "\n\n");
497 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
500 struct thread_list_t *cur;
503 e->command = "core show threads";
505 "Usage: core show threads\n"
506 " List threads currently active in the system.\n";
512 AST_RWLIST_RDLOCK(&thread_list);
513 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
514 ast_cli(a->fd, "%p %s\n", (void *)cur->id, cur->name);
517 AST_RWLIST_UNLOCK(&thread_list);
518 ast_cli(a->fd, "%d threads listed.\n", count);
522 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
524 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
525 * to be based on the new swapctl(2) system call.
527 static int swapmode(int *used, int *total)
529 struct swapent *swdev;
530 int nswap, rnswap, i;
532 nswap = swapctl(SWAP_NSWAP, 0, 0);
536 swdev = ast_calloc(nswap, sizeof(*swdev));
540 rnswap = swapctl(SWAP_STATS, swdev, nswap);
546 /* if rnswap != nswap, then what? */
548 /* Total things up */
550 for (i = 0; i < nswap; i++) {
551 if (swdev[i].se_flags & SWF_ENABLE) {
552 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
553 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
559 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
560 static int swapmode(int *used, int *total)
567 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
568 /*! \brief Give an overview of system statistics */
569 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
571 int64_t physmem, freeram;
572 int totalswap = 0, freeswap = 0, nprocs = 0;
574 #if defined(HAVE_SYSINFO)
575 struct sysinfo sys_info;
577 uptime = sys_info.uptime/3600;
578 physmem = sys_info.totalram * sys_info.mem_unit;
579 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
580 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
581 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
582 nprocs = sys_info.procs;
583 #elif defined(HAVE_SYSCTL)
584 static int pageshift;
585 struct vmtotal vmtotal;
586 struct timeval boottime;
588 int mib[2], pagesize, usedswap = 0;
590 /* calculate the uptime by looking at boottime */
593 mib[1] = KERN_BOOTTIME;
594 len = sizeof(boottime);
595 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
596 uptime = now - boottime.tv_sec;
598 uptime = uptime/3600;
599 /* grab total physical memory */
601 #if defined(HW_PHYSMEM64)
602 mib[1] = HW_PHYSMEM64;
606 len = sizeof(physmem);
607 sysctl(mib, 2, &physmem, &len, NULL, 0);
609 pagesize = getpagesize();
611 while (pagesize > 1) {
616 /* we only need the amount of log(2)1024 for our conversion */
622 len = sizeof(vmtotal);
623 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
624 freeram = (vmtotal.t_free << pageshift);
625 /* generate swap usage and totals */
626 swapmode(&usedswap, &totalswap);
627 freeswap = (totalswap - usedswap);
628 /* grab number of processes */
629 #if defined(__OpenBSD__)
631 mib[1] = KERN_NPROCS;
632 len = sizeof(nprocs);
633 sysctl(mib, 2, &nprocs, &len, NULL, 0);
639 e->command = "core show sysinfo";
641 "Usage: core show sysinfo\n"
642 " List current system information.\n";
648 ast_cli(a->fd, "\nSystem Statistics\n");
649 ast_cli(a->fd, "-----------------\n");
650 ast_cli(a->fd, " System Uptime: %ld hours\n", uptime);
651 ast_cli(a->fd, " Total RAM: %ld KiB\n", (long)physmem/1024);
652 ast_cli(a->fd, " Free RAM: %ld KiB\n", (long)freeram);
653 #if defined(HAVE_SYSINFO)
654 ast_cli(a->fd, " Buffer RAM: %ld KiB\n", (sys_info.bufferram * sys_info.mem_unit)/1024);
656 ast_cli(a->fd, " Total Swap Space: %ld KiB\n", (long)totalswap);
657 ast_cli(a->fd, " Free Swap Space: %ld KiB\n\n", (long)freeswap);
658 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
663 struct profile_entry {
665 uint64_t scale; /* if non-zero, values are scaled by this */
671 struct profile_data {
674 struct profile_entry e[0];
677 static struct profile_data *prof_data;
679 /*! \brief allocates a counter with a given name and scale.
680 * \return Returns the identifier of the counter.
682 int ast_add_profile(const char *name, uint64_t scale)
684 int l = sizeof(struct profile_data);
685 int n = 10; /* default entries */
687 if (prof_data == NULL) {
688 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
689 if (prof_data == NULL)
691 prof_data->entries = 0;
692 prof_data->max_size = n;
694 if (prof_data->entries >= prof_data->max_size) {
696 n = prof_data->max_size + 20;
697 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
701 prof_data->max_size = n;
703 n = prof_data->entries++;
704 prof_data->e[n].name = ast_strdup(name);
705 prof_data->e[n].value = 0;
706 prof_data->e[n].events = 0;
707 prof_data->e[n].mark = 0;
708 prof_data->e[n].scale = scale;
712 int64_t ast_profile(int i, int64_t delta)
714 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
716 if (prof_data->e[i].scale > 1)
717 delta /= prof_data->e[i].scale;
718 prof_data->e[i].value += delta;
719 prof_data->e[i].events++;
720 return prof_data->e[i].value;
723 /* The RDTSC instruction was introduced on the Pentium processor and is not
724 * implemented on certain clones, like the Cyrix 586. Hence, the previous
725 * expectation of __i386__ was in error. */
726 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
727 #if defined(__FreeBSD__)
728 #include <machine/cpufunc.h>
730 static __inline uint64_t
735 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
739 #else /* supply a dummy function on other platforms */
740 static __inline uint64_t
747 int64_t ast_mark(int i, int startstop)
749 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
752 prof_data->e[i].mark = rdtsc();
754 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
755 if (prof_data->e[i].scale > 1)
756 prof_data->e[i].mark /= prof_data->e[i].scale;
757 prof_data->e[i].value += prof_data->e[i].mark;
758 prof_data->e[i].events++;
760 return prof_data->e[i].mark;
763 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
764 max = prof_data->entries;\
765 if (a->argc > 3) { /* specific entries */ \
766 if (isdigit(a->argv[3][0])) { \
767 min = atoi(a->argv[3]); \
768 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
769 max = atoi(a->argv[4]); \
771 search = a->argv[3]; \
773 if (max > prof_data->entries) \
774 max = prof_data->entries;
776 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
779 const char *search = NULL;
782 e->command = "core show profile";
783 e->usage = "Usage: core show profile\n"
784 " show profile information";
790 if (prof_data == NULL)
793 DEFINE_PROFILE_MIN_MAX_VALUES;
794 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
795 prof_data->entries, prof_data->max_size);
796 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
797 "Value", "Average", "Name");
798 for (i = min; i < max; i++) {
799 struct profile_entry *entry = &prof_data->e[i];
800 if (!search || strstr(entry->name, search))
801 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
804 (long)entry->events, (long long)entry->value,
805 (long long)(entry->events ? entry->value / entry->events : entry->value),
811 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
814 const char *search = NULL;
817 e->command = "core clear profile";
818 e->usage = "Usage: core clear profile\n"
819 " clear profile information";
825 if (prof_data == NULL)
828 DEFINE_PROFILE_MIN_MAX_VALUES;
829 for (i= min; i < max; i++) {
830 if (!search || strstr(prof_data->e[i].name, search)) {
831 prof_data->e[i].value = 0;
832 prof_data->e[i].events = 0;
837 #undef DEFINE_PROFILE_MIN_MAX_VALUES
839 /*! \brief CLI command to list module versions */
840 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
842 #define FORMAT "%-25.25s %-40.40s\n"
843 struct file_version *iterator;
849 int matchlen, which = 0;
850 struct file_version *find;
854 e->command = "core show file version [like]";
856 "Usage: core show file version [like <pattern>]\n"
857 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
858 " Optional regular expression pattern is used to filter the file list.\n";
861 matchlen = strlen(a->word);
864 AST_RWLIST_RDLOCK(&file_versions);
865 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
866 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
867 ret = ast_strdup(find->file);
871 AST_RWLIST_UNLOCK(&file_versions);
878 if (!strcasecmp(a->argv[4], "like")) {
879 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
880 return CLI_SHOWUSAGE;
883 return CLI_SHOWUSAGE;
891 return CLI_SHOWUSAGE;
894 ast_cli(a->fd, FORMAT, "File", "Revision");
895 ast_cli(a->fd, FORMAT, "----", "--------");
896 AST_RWLIST_RDLOCK(&file_versions);
897 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
898 if (havename && strcasecmp(iterator->file, a->argv[4]))
901 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
904 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
909 AST_RWLIST_UNLOCK(&file_versions);
911 ast_cli(a->fd, "%d files listed.\n", count_files);
921 #endif /* ! LOW_MEMORY */
923 int ast_register_atexit(void (*func)(void))
925 struct ast_atexit *ae;
927 if (!(ae = ast_calloc(1, sizeof(*ae))))
932 ast_unregister_atexit(func);
934 AST_RWLIST_WRLOCK(&atexits);
935 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
936 AST_RWLIST_UNLOCK(&atexits);
941 void ast_unregister_atexit(void (*func)(void))
943 struct ast_atexit *ae = NULL;
945 AST_RWLIST_WRLOCK(&atexits);
946 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
947 if (ae->func == func) {
948 AST_RWLIST_REMOVE_CURRENT(list);
952 AST_RWLIST_TRAVERSE_SAFE_END;
953 AST_RWLIST_UNLOCK(&atexits);
958 /* Sending commands from consoles back to the daemon requires a terminating NULL */
959 static int fdsend(int fd, const char *s)
961 return write(fd, s, strlen(s) + 1);
964 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
965 static int fdprint(int fd, const char *s)
967 return write(fd, s, strlen(s));
970 /*! \brief NULL handler so we can collect the child exit status */
971 static void null_sig_handler(int sig)
976 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
977 /*! \brief Keep track of how many threads are currently trying to wait*() on
979 static unsigned int safe_system_level = 0;
980 static void *safe_system_prev_handler;
982 void ast_replace_sigchld(void)
986 ast_mutex_lock(&safe_system_lock);
987 level = safe_system_level++;
989 /* only replace the handler if it has not already been done */
991 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
993 ast_mutex_unlock(&safe_system_lock);
996 void ast_unreplace_sigchld(void)
1000 ast_mutex_lock(&safe_system_lock);
1001 level = --safe_system_level;
1003 /* only restore the handler if we are the last one */
1005 signal(SIGCHLD, safe_system_prev_handler);
1007 ast_mutex_unlock(&safe_system_lock);
1010 int ast_safe_system(const char *s)
1014 struct rusage rusage;
1017 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1018 ast_replace_sigchld();
1020 #ifdef HAVE_WORKING_FORK
1028 cap_t cap = cap_from_text("cap_net_admin-eip");
1030 if (cap_set_proc(cap)) {
1031 /* Careful with order! Logging cannot happen after we close FDs */
1032 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1036 #ifdef HAVE_WORKING_FORK
1037 if (ast_opt_high_priority)
1038 ast_set_priority(0);
1039 /* Close file descriptors and launch system command */
1040 ast_close_fds_above_n(STDERR_FILENO);
1042 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1044 } else if (pid > 0) {
1046 res = wait4(pid, &status, 0, &rusage);
1048 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1050 } else if (errno != EINTR)
1054 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1058 ast_unreplace_sigchld();
1059 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1066 void ast_console_toggle_loglevel(int fd, int level, int state)
1069 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1070 if (fd == consoles[x].fd) {
1071 consoles[x].levels[level] = state;
1078 * \brief mute or unmute a console from logging
1080 void ast_console_toggle_mute(int fd, int silent) {
1082 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1083 if (fd == consoles[x].fd) {
1084 if (consoles[x].mute) {
1085 consoles[x].mute = 0;
1087 ast_cli(fd, "Console is not muted anymore.\n");
1089 consoles[x].mute = 1;
1091 ast_cli(fd, "Console is muted.\n");
1096 ast_cli(fd, "Couldn't find remote console.\n");
1100 * \brief log the string to all attached console clients
1102 static void ast_network_puts_mutable(const char *string, int level)
1105 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1106 if (consoles[x].mute)
1108 if (consoles[x].fd > -1) {
1109 if (!consoles[x].levels[level])
1110 fdprint(consoles[x].p[1], string);
1116 * \brief log the string to the console, and all attached
1119 void ast_console_puts_mutable(const char *string, int level)
1121 fputs(string, stdout);
1123 ast_network_puts_mutable(string, level);
1127 * \brief write the string to all attached console clients
1129 static void ast_network_puts(const char *string)
1132 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1133 if (consoles[x].fd > -1)
1134 fdprint(consoles[x].p[1], string);
1139 * write the string to the console, and all attached
1142 void ast_console_puts(const char *string)
1144 fputs(string, stdout);
1146 ast_network_puts(string);
1149 static void network_verboser(const char *s)
1151 ast_network_puts_mutable(s, __LOG_VERBOSE);
1154 static pthread_t lthread;
1157 * \brief read() function supporting the reception of user credentials.
1159 * \param fd Socket file descriptor.
1160 * \param buffer Receive buffer.
1161 * \param size 'buffer' size.
1162 * \param con Console structure to set received credentials
1163 * \retval -1 on error
1164 * \retval the number of bytes received on success.
1166 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1168 #if defined(SO_PEERCRED)
1170 socklen_t len = sizeof(cred);
1172 #if defined(HAVE_GETPEEREID)
1180 result = read(fd, buffer, size);
1185 #if defined(SO_PEERCRED)
1186 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1191 #elif defined(HAVE_GETPEEREID)
1192 if (getpeereid(fd, &uid, &gid)) {
1204 static void *netconsole(void *vconsole)
1206 struct console *con = vconsole;
1207 char hostname[MAXHOSTNAMELEN] = "";
1210 struct pollfd fds[2];
1212 if (gethostname(hostname, sizeof(hostname)-1))
1213 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1214 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1215 fdprint(con->fd, tmp);
1217 fds[0].fd = con->fd;
1218 fds[0].events = POLLIN;
1220 fds[1].fd = con->p[0];
1221 fds[1].events = POLLIN;
1224 res = ast_poll(fds, 2, -1);
1227 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1230 if (fds[0].revents) {
1231 res = read_credentials(con->fd, tmp, sizeof(tmp) - 1, con);
1236 if (strncmp(tmp, "cli quit after ", 15) == 0) {
1237 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res - 15, tmp + 15);
1240 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, res, tmp);
1242 if (fds[1].revents) {
1243 res = read_credentials(con->p[0], tmp, sizeof(tmp), con);
1245 ast_log(LOG_ERROR, "read returned %d\n", res);
1248 res = write(con->fd, tmp, res);
1253 if (!ast_opt_hide_connect) {
1254 ast_verb(3, "Remote UNIX connection disconnected\n");
1264 static void *listener(void *unused)
1266 struct sockaddr_un sunaddr;
1271 struct pollfd fds[1];
1275 fds[0].fd = ast_socket;
1276 fds[0].events = POLLIN;
1277 s = ast_poll(fds, 1, -1);
1278 pthread_testcancel();
1281 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1284 len = sizeof(sunaddr);
1285 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1288 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1290 #if !defined(SO_PASSCRED)
1294 /* turn on socket credentials passing. */
1295 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1296 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1299 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1300 if (consoles[x].fd >= 0) {
1303 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1304 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1305 consoles[x].fd = -1;
1306 fdprint(s, "Server failed to create pipe\n");
1310 flags = fcntl(consoles[x].p[1], F_GETFL);
1311 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1313 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1314 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1315 to know if the user didn't send the credentials. */
1316 consoles[x].uid = -2;
1317 consoles[x].gid = -2;
1318 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1319 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1320 close(consoles[x].p[0]);
1321 close(consoles[x].p[1]);
1322 consoles[x].fd = -1;
1323 fdprint(s, "Server failed to spawn thread\n");
1328 if (x >= AST_MAX_CONNECTS) {
1329 fdprint(s, "No more connections allowed\n");
1330 ast_log(LOG_WARNING, "No more connections allowed\n");
1332 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1333 ast_verb(3, "Remote UNIX connection\n");
1341 static int ast_makesocket(void)
1343 struct sockaddr_un sunaddr;
1349 for (x = 0; x < AST_MAX_CONNECTS; x++)
1350 consoles[x].fd = -1;
1351 unlink(ast_config_AST_SOCKET);
1352 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1353 if (ast_socket < 0) {
1354 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1357 memset(&sunaddr, 0, sizeof(sunaddr));
1358 sunaddr.sun_family = AF_LOCAL;
1359 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1360 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1362 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1367 res = listen(ast_socket, 2);
1369 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1374 if (ast_register_verbose(network_verboser)) {
1375 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1378 ast_pthread_create_background(<hread, NULL, listener, NULL);
1380 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1382 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1383 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1388 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1390 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1391 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1396 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1397 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1399 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1402 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1404 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1405 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1411 static int ast_tryconnect(void)
1413 struct sockaddr_un sunaddr;
1415 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1416 if (ast_consock < 0) {
1417 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1420 memset(&sunaddr, 0, sizeof(sunaddr));
1421 sunaddr.sun_family = AF_LOCAL;
1422 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1423 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1432 /*! \brief Urgent handler
1434 Called by soft_hangup to interrupt the poll, read, or other
1435 system call. We don't actually need to do anything though.
1436 Remember: Cannot EVER ast_log from within a signal handler
1438 static void urg_handler(int num)
1440 signal(num, urg_handler);
1444 static void hup_handler(int num)
1447 if (option_verbose > 1)
1448 printf("Received HUP signal -- Reloading configs\n");
1450 execvp(_argv[0], _argv);
1451 sig_flags.need_reload = 1;
1452 if (sig_alert_pipe[1] != -1) {
1453 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1454 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1457 signal(num, hup_handler);
1460 static void child_handler(int sig)
1462 /* Must not ever ast_log or ast_verbose within signal handler */
1466 * Reap all dead children -- not just one
1468 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1470 if (n == 0 && option_debug)
1471 printf("Huh? Child handler, but nobody there?\n");
1472 signal(sig, child_handler);
1475 /*! \brief Set maximum open files */
1476 static void set_ulimit(int value)
1478 struct rlimit l = {0, 0};
1481 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1488 if (setrlimit(RLIMIT_NOFILE, &l)) {
1489 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1493 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1498 /*! \brief Set an X-term or screen title */
1499 static void set_title(char *text)
1501 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1502 fprintf(stdout, "\033]2;%s\007", text);
1505 static void set_icon(char *text)
1507 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1508 fprintf(stdout, "\033]1;%s\007", text);
1511 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1512 else. If your PBX has heavy activity on it, this is a good thing. */
1513 int ast_set_priority(int pri)
1515 struct sched_param sched;
1516 memset(&sched, 0, sizeof(sched));
1519 sched.sched_priority = 10;
1520 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1521 ast_log(LOG_WARNING, "Unable to set high priority\n");
1525 ast_verbose("Set to realtime thread\n");
1527 sched.sched_priority = 0;
1528 /* According to the manpage, these parameters can never fail. */
1529 sched_setscheduler(0, SCHED_OTHER, &sched);
1533 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1534 ast_log(LOG_WARNING, "Unable to set high priority\n");
1538 ast_verbose("Set to high priority\n");
1540 /* According to the manpage, these parameters can never fail. */
1541 setpriority(PRIO_PROCESS, 0, 0);
1547 static void ast_run_atexits(void)
1549 struct ast_atexit *ae;
1550 AST_RWLIST_RDLOCK(&atexits);
1551 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1555 AST_RWLIST_UNLOCK(&atexits);
1558 static void quit_handler(int num, int niceness, int safeshutdown, int restart)
1560 char filename[80] = "";
1563 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1564 ast_cdr_engine_term();
1568 /* Begin shutdown routine, hanging up active channels */
1569 ast_begin_shutdown(1);
1570 if (option_verbose && ast_opt_console)
1571 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1575 /* Wait up to 15 seconds for all channels to go away */
1578 if (!ast_active_channels())
1582 /* Sleep 1/10 of a second */
1587 ast_begin_shutdown(0);
1588 if (option_verbose && ast_opt_console)
1589 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1591 if (!ast_active_channels())
1599 if (!shuttingdown) {
1600 if (option_verbose && ast_opt_console)
1601 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1606 ast_module_shutdown();
1608 if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1610 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1611 if (!ast_strlen_zero(filename))
1612 ast_el_write_history(filename);
1615 if (el_hist != NULL)
1616 history_end(el_hist);
1619 ast_verbose("Executing last minute cleanups\n");
1621 /* Called on exit */
1622 if (option_verbose && ast_opt_console)
1623 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1624 ast_debug(1, "Asterisk ending (%d).\n", num);
1625 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1626 if (ast_socket > -1) {
1627 pthread_cancel(lthread);
1630 unlink(ast_config_AST_SOCKET);
1632 if (ast_consock > -1)
1634 if (!ast_opt_remote)
1635 unlink(ast_config_AST_PID);
1636 printf("%s", term_quit());
1638 if (option_verbose || ast_opt_console)
1639 ast_verbose("Preparing for Asterisk restart...\n");
1640 /* Mark all FD's for closing on exec */
1641 for (x=3; x < 32768; x++) {
1642 fcntl(x, F_SETFD, FD_CLOEXEC);
1644 if (option_verbose || ast_opt_console)
1645 ast_verbose("Asterisk is now restarting...\n");
1651 /* If there is a consolethread running send it a SIGHUP
1652 so it can execvp, otherwise we can do it ourselves */
1653 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1654 pthread_kill(consolethread, SIGHUP);
1655 /* Give the signal handler some time to complete */
1658 execvp(_argv[0], _argv);
1667 static void __quit_handler(int num)
1670 sig_flags.need_quit = 1;
1671 if (sig_alert_pipe[1] != -1) {
1672 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1673 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1676 /* There is no need to restore the signal handler here, since the app
1677 * is going to exit */
1680 static void __remote_quit_handler(int num)
1682 sig_flags.need_quit = 1;
1685 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1689 /* Check for verboser preamble */
1694 if (!strncmp(s, cmp, strlen(cmp))) {
1695 c = s + strlen(cmp);
1696 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1702 static void console_verboser(const char *s)
1705 const char *c = NULL;
1707 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1708 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1709 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1710 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1722 /* Wake up a poll()ing console */
1723 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1724 pthread_kill(consolethread, SIGURG);
1727 static int ast_all_zeros(char *s)
1737 static void consolehandler(char *s)
1739 printf("%s", term_end());
1742 /* Called when readline data is available */
1743 if (!ast_all_zeros(s))
1744 ast_el_add_history(s);
1745 /* The real handler for bang */
1748 ast_safe_system(s+1);
1750 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1752 ast_cli_command(STDOUT_FILENO, s);
1755 static int remoteconsolehandler(char *s)
1759 /* Called when readline data is available */
1760 if (!ast_all_zeros(s))
1761 ast_el_add_history(s);
1762 /* The real handler for bang */
1765 ast_safe_system(s+1);
1767 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1770 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1771 (s[4] == '\0' || isspace(s[4]))) {
1772 quit_handler(0, 0, 0, 0);
1779 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1783 e->command = "core show version";
1785 "Usage: core show version\n"
1786 " Shows Asterisk version information.\n";
1793 return CLI_SHOWUSAGE;
1794 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1795 ast_get_version(), ast_build_user, ast_build_hostname,
1796 ast_build_machine, ast_build_os, ast_build_date);
1801 static int handle_quit(int fd, int argc, char *argv[])
1804 return RESULT_SHOWUSAGE;
1805 quit_handler(0, 0, 1, 0);
1806 return RESULT_SUCCESS;
1810 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1814 e->command = "core stop now";
1816 "Usage: core stop now\n"
1817 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1823 if (a->argc != e->args)
1824 return CLI_SHOWUSAGE;
1825 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1829 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1833 e->command = "core stop gracefully";
1835 "Usage: core stop gracefully\n"
1836 " Causes Asterisk to not accept new calls, and exit when all\n"
1837 " active calls have terminated normally.\n";
1843 if (a->argc != e->args)
1844 return CLI_SHOWUSAGE;
1845 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1849 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1853 e->command = "core stop when convenient";
1855 "Usage: core stop when convenient\n"
1856 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1862 if (a->argc != e->args)
1863 return CLI_SHOWUSAGE;
1864 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
1865 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1869 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1873 e->command = "core restart now";
1875 "Usage: core restart now\n"
1876 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1883 if (a->argc != e->args)
1884 return CLI_SHOWUSAGE;
1885 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1889 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1893 e->command = "core restart gracefully";
1895 "Usage: core restart gracefully\n"
1896 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1897 " restart when all active calls have ended.\n";
1903 if (a->argc != e->args)
1904 return CLI_SHOWUSAGE;
1905 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1909 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1913 e->command = "core restart when convenient";
1915 "Usage: core restart when convenient\n"
1916 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1922 if (a->argc != e->args)
1923 return CLI_SHOWUSAGE;
1924 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
1925 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1929 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1933 e->command = "core abort shutdown";
1935 "Usage: core abort shutdown\n"
1936 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1937 " call operations.\n";
1943 if (a->argc != e->args)
1944 return CLI_SHOWUSAGE;
1945 ast_cancel_shutdown();
1950 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1956 "Usage: !<command>\n"
1957 " Executes a given shell command\n";
1965 static const char warranty_lines[] = {
1969 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
1970 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
1971 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
1972 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
1973 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
1974 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
1975 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
1976 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
1977 "REPAIR OR CORRECTION.\n"
1979 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
1980 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
1981 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
1982 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
1983 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
1984 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
1985 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
1986 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
1987 "POSSIBILITY OF SUCH DAMAGES.\n"
1990 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1994 e->command = "core show warranty";
1996 "Usage: core show warranty\n"
1997 " Shows the warranty (if any) for this copy of Asterisk.\n";
2003 ast_cli(a->fd, "%s", warranty_lines);
2008 static const char license_lines[] = {
2010 "This program is free software; you can redistribute it and/or modify\n"
2011 "it under the terms of the GNU General Public License version 2 as\n"
2012 "published by the Free Software Foundation.\n"
2014 "This program also contains components licensed under other licenses.\n"
2017 "This program is distributed in the hope that it will be useful,\n"
2018 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2019 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2020 "GNU General Public License for more details.\n"
2022 "You should have received a copy of the GNU General Public License\n"
2023 "along with this program; if not, write to the Free Software\n"
2024 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2027 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2031 e->command = "core show license";
2033 "Usage: core show license\n"
2034 " Shows the license(s) for this copy of Asterisk.\n";
2040 ast_cli(a->fd, "%s", license_lines);
2045 #define ASTERISK_PROMPT "*CLI> "
2047 #define ASTERISK_PROMPT2 "%s*CLI> "
2049 static struct ast_cli_entry cli_asterisk[] = {
2050 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2051 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2052 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2053 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2054 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2055 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2056 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2057 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2058 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2059 AST_CLI_DEFINE(handle_version, "Display version info"),
2060 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2061 #if !defined(LOW_MEMORY)
2062 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2063 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2064 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2065 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2067 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2068 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2069 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2070 #endif /* ! LOW_MEMORY */
2073 static int ast_el_read_char(EditLine *editline, char *cp)
2077 struct pollfd fds[2];
2080 #define EL_BUF_SIZE 512
2081 char buf[EL_BUF_SIZE];
2085 fds[0].fd = ast_consock;
2086 fds[0].events = POLLIN;
2087 if (!ast_opt_exec) {
2088 fds[1].fd = STDIN_FILENO;
2089 fds[1].events = POLLIN;
2092 res = ast_poll(fds, max, -1);
2094 if (sig_flags.need_quit)
2098 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2102 if (!ast_opt_exec && fds[1].revents) {
2103 num_read = read(STDIN_FILENO, cp, 1);
2109 if (fds[0].revents) {
2111 res = read(ast_consock, buf, sizeof(buf) - 1);
2112 /* if the remote side disappears exit */
2114 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2115 if (!ast_opt_reconnect) {
2116 quit_handler(0, 0, 0, 0);
2119 int reconnects_per_second = 20;
2120 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2121 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2122 if (ast_tryconnect()) {
2123 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2124 printf("%s", term_quit());
2127 fdsend(ast_consock, "logger mute silent");
2129 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2132 usleep(1000000 / reconnects_per_second);
2134 if (tries >= 30 * reconnects_per_second) {
2135 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2136 quit_handler(0, 0, 0, 0);
2143 /* Strip preamble from asynchronous events, too */
2144 for (tmp = buf; *tmp; tmp++) {
2146 memmove(tmp, tmp + 1, strlen(tmp));
2152 /* Write over the CLI prompt */
2153 if (!ast_opt_exec && !lastpos) {
2154 if (write(STDOUT_FILENO, "\r", 1) < 0) {
2157 if (write(STDOUT_FILENO, buf, res) < 0) {
2159 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2171 static struct ast_str *prompt = NULL;
2173 static char *cli_prompt(EditLine *editline)
2178 static int cli_prompt_changes = 0;
2183 if (prompt == NULL) {
2184 prompt = ast_str_create(100);
2185 } else if (!cli_prompt_changes) {
2186 return ast_str_buffer(prompt);
2188 ast_str_reset(prompt);
2191 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2193 struct timeval ts = ast_tvnow();
2194 while (*t != '\0') {
2196 char hostname[MAXHOSTNAMELEN] = "";
2198 struct ast_tm tm = { 0, };
2199 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2203 case 'C': /* color */
2205 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2206 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2208 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2209 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2213 /* If the color has been reset correctly, then there's no need to reset it later */
2214 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2216 case 'd': /* date */
2217 if (ast_localtime(&ts, &tm, NULL)) {
2218 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2219 ast_str_append(&prompt, 0, "%s", tmp);
2220 cli_prompt_changes++;
2223 case 'g': /* group */
2224 if ((gr = getgrgid(getgid()))) {
2225 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2228 case 'h': /* hostname */
2229 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2230 ast_str_append(&prompt, 0, "%s", hostname);
2232 ast_str_append(&prompt, 0, "%s", "localhost");
2235 case 'H': /* short hostname */
2236 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2238 if ((dotptr = strchr(hostname, '.'))) {
2241 ast_str_append(&prompt, 0, "%s", hostname);
2243 ast_str_append(&prompt, 0, "%s", "localhost");
2246 #ifdef HAVE_GETLOADAVG
2247 case 'l': /* load avg */
2249 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2251 getloadavg(list, 3);
2252 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2253 cli_prompt_changes++;
2257 case 's': /* Asterisk system name (from asterisk.conf) */
2258 ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2260 case 't': /* time */
2261 if (ast_localtime(&ts, &tm, NULL)) {
2262 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2263 ast_str_append(&prompt, 0, "%s", tmp);
2264 cli_prompt_changes++;
2267 case 'u': /* username */
2268 if ((pw = getpwuid(getuid()))) {
2269 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2272 case '#': /* process console or remote? */
2273 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2275 case '%': /* literal % */
2276 ast_str_append(&prompt, 0, "%c", '%');
2278 case '\0': /* % is last character - prevent bug */
2283 ast_str_append(&prompt, 0, "%c", *t);
2288 /* Force colors back to normal at end */
2289 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2291 } else if (remotehostname) {
2292 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2294 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2297 return ast_str_buffer(prompt);
2300 static char **ast_el_strtoarr(char *buf)
2302 char **match_list = NULL, **match_list_tmp, *retstr;
2303 size_t match_list_len;
2307 while ( (retstr = strsep(&buf, " ")) != NULL) {
2309 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2311 if (matches + 1 >= match_list_len) {
2312 match_list_len <<= 1;
2313 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2314 match_list = match_list_tmp;
2317 ast_free(match_list);
2318 return (char **) NULL;
2322 match_list[matches++] = ast_strdup(retstr);
2326 return (char **) NULL;
2328 if (matches >= match_list_len) {
2329 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2330 match_list = match_list_tmp;
2333 ast_free(match_list);
2334 return (char **) NULL;
2338 match_list[matches] = (char *) NULL;
2343 static int ast_el_sort_compare(const void *i1, const void *i2)
2347 s1 = ((char **)i1)[0];
2348 s2 = ((char **)i2)[0];
2350 return strcasecmp(s1, s2);
2353 static int ast_cli_display_match_list(char **matches, int len, int max)
2355 int i, idx, limit, count;
2356 int screenwidth = 0;
2357 int numoutput = 0, numoutputline = 0;
2359 screenwidth = ast_get_termcols(STDOUT_FILENO);
2361 /* find out how many entries can be put on one line, with two spaces between strings */
2362 limit = screenwidth / (max + 2);
2366 /* how many lines of output */
2367 count = len / limit;
2368 if (count * limit < len)
2373 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2375 for (; count > 0; count--) {
2377 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2379 /* Don't print dupes */
2380 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2382 ast_free(matches[idx]);
2383 matches[idx] = NULL;
2389 fprintf(stdout, "%-*s ", max, matches[idx]);
2390 ast_free(matches[idx]);
2391 matches[idx] = NULL;
2393 if (numoutputline > 0)
2394 fprintf(stdout, "\n");
2401 static char *cli_complete(EditLine *editline, int ch)
2407 int retval = CC_ERROR;
2408 char buf[2048], savechr;
2411 LineInfo *lf = (LineInfo *)el_line(editline);
2413 savechr = *(char *)lf->cursor;
2414 *(char *)lf->cursor = '\0';
2415 ptr = (char *)lf->cursor;
2417 while (ptr > lf->buffer) {
2418 if (isspace(*ptr)) {
2426 len = lf->cursor - ptr;
2428 if (ast_opt_remote) {
2429 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2430 fdsend(ast_consock, buf);
2431 res = read(ast_consock, buf, sizeof(buf) - 1);
2433 nummatches = atoi(buf);
2435 if (nummatches > 0) {
2437 int mlen = 0, maxmbuf = 2048;
2438 /* Start with a 2048 byte buffer */
2439 if (!(mbuf = ast_malloc(maxmbuf))) {
2440 lf->cursor[0] = savechr;
2441 return (char *)(CC_ERROR);
2443 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2444 fdsend(ast_consock, buf);
2447 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2448 if (mlen + 1024 > maxmbuf) {
2449 /* Every step increment buffer 1024 bytes */
2451 if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2452 lf->cursor[0] = savechr;
2453 return (char *)(CC_ERROR);
2456 /* Only read 1024 bytes at a time */
2457 res = read(ast_consock, mbuf + mlen, 1024);
2463 matches = ast_el_strtoarr(mbuf);
2466 matches = (char **) NULL;
2468 char **p, *oldbuf=NULL;
2470 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2471 for (p = matches; p && *p; p++) {
2472 if (!oldbuf || strcmp(*p,oldbuf))
2480 int matches_num, maxlen, match_len;
2482 if (matches[0][0] != '\0') {
2483 el_deletestr(editline, (int) len);
2484 el_insertstr(editline, matches[0]);
2485 retval = CC_REFRESH;
2488 if (nummatches == 1) {
2489 /* Found an exact match */
2490 el_insertstr(editline, " ");
2491 retval = CC_REFRESH;
2493 /* Must be more than one match */
2494 for (i = 1, maxlen = 0; matches[i]; i++) {
2495 match_len = strlen(matches[i]);
2496 if (match_len > maxlen)
2499 matches_num = i - 1;
2500 if (matches_num >1) {
2501 fprintf(stdout, "\n");
2502 ast_cli_display_match_list(matches, nummatches, maxlen);
2503 retval = CC_REDISPLAY;
2505 el_insertstr(editline," ");
2506 retval = CC_REFRESH;
2509 for (i = 0; matches[i]; i++)
2510 ast_free(matches[i]);
2514 lf->cursor[0] = savechr;
2516 return (char *)(long)retval;
2519 static int ast_el_initialize(void)
2522 char *editor = getenv("AST_EDITOR");
2526 if (el_hist != NULL)
2527 history_end(el_hist);
2529 el = el_init("asterisk", stdin, stdout, stderr);
2530 el_set(el, EL_PROMPT, cli_prompt);
2532 el_set(el, EL_EDITMODE, 1);
2533 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2534 el_hist = history_init();
2535 if (!el || !el_hist)
2538 /* setup history with 100 entries */
2539 history(el_hist, &ev, H_SETSIZE, 100);
2541 el_set(el, EL_HIST, history, el_hist);
2543 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2544 /* Bind <tab> to command completion */
2545 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2546 /* Bind ? to command completion */
2547 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2548 /* Bind ^D to redisplay */
2549 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2554 #define MAX_HISTORY_COMMAND_LENGTH 256
2556 static int ast_el_add_history(char *buf)
2560 if (el_hist == NULL || el == NULL)
2561 ast_el_initialize();
2562 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2564 return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2567 static int ast_el_write_history(char *filename)
2571 if (el_hist == NULL || el == NULL)
2572 ast_el_initialize();
2574 return (history(el_hist, &ev, H_SAVE, filename));
2577 static int ast_el_read_history(char *filename)
2579 char buf[MAX_HISTORY_COMMAND_LENGTH];
2583 if (el_hist == NULL || el == NULL)
2584 ast_el_initialize();
2586 if ((f = fopen(filename, "r")) == NULL)
2590 if (!fgets(buf, sizeof(buf), f))
2592 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2594 if (ast_all_zeros(buf))
2596 if ((ret = ast_el_add_history(buf)) == -1)
2604 static void ast_remotecontrol(char *data)
2608 char filename[80] = "";
2613 char *stringp = NULL;
2618 memset(&sig_flags, 0, sizeof(sig_flags));
2619 signal(SIGINT, __remote_quit_handler);
2620 signal(SIGTERM, __remote_quit_handler);
2621 signal(SIGHUP, __remote_quit_handler);
2623 if (read(ast_consock, buf, sizeof(buf)) < 0) {
2624 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2628 char prefix[] = "cli quit after ";
2629 char *tmp = alloca(strlen(data) + strlen(prefix) + 1);
2630 sprintf(tmp, "%s%s", prefix, data);
2631 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2632 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2633 if (sig_flags.need_quit == 1) {
2639 hostname = strsep(&stringp, "/");
2640 cpid = strsep(&stringp, "/");
2641 version = strsep(&stringp, "\n");
2643 version = "<Version Unknown>";
2645 strsep(&stringp, ".");
2652 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2653 fdsend(ast_consock, tmp);
2654 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2655 fdsend(ast_consock, tmp);
2657 fdsend(ast_consock, "logger mute silent");
2659 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2662 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2664 fds.fd = ast_consock;
2665 fds.events = POLLIN;
2667 while (ast_poll(&fds, 1, 60000) > 0) {
2668 char buffer[512] = "", *curline = buffer, *nextline;
2669 int not_written = 1;
2671 if (sig_flags.need_quit == 1) {
2675 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
2680 if ((nextline = strchr(curline, '\n'))) {
2683 nextline = strchr(curline, '\0');
2686 /* Skip verbose lines */
2687 if (*curline != 127) {
2689 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2690 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
2694 } while (!ast_strlen_zero(curline));
2696 /* No non-verbose output in 60 seconds. */
2704 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2705 remotehostname = hostname;
2707 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2708 if (el_hist == NULL || el == NULL)
2709 ast_el_initialize();
2711 el_set(el, EL_GETCFN, ast_el_read_char);
2713 if (!ast_strlen_zero(filename))
2714 ast_el_read_history(filename);
2717 ebuf = (char *)el_gets(el, &num);
2719 if (sig_flags.need_quit == 1) {
2723 if (!ebuf && write(1, "", 1) < 0)
2726 if (!ast_strlen_zero(ebuf)) {
2727 if (ebuf[strlen(ebuf)-1] == '\n')
2728 ebuf[strlen(ebuf)-1] = '\0';
2729 if (!remoteconsolehandler(ebuf)) {
2730 /* Strip preamble from output */
2732 for (temp = ebuf; *temp; temp++) {
2734 memmove(temp, temp + 1, strlen(temp));
2738 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2740 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2746 printf("\nDisconnected from Asterisk server\n");
2749 static int show_version(void)
2751 printf("Asterisk %s\n", ast_get_version());
2755 static int show_cli_help(void) {
2756 printf("Asterisk %s, Copyright (C) 1999 - 2010, Digium, Inc. and others.\n", ast_get_version());
2757 printf("Usage: asterisk [OPTIONS]\n");
2758 printf("Valid Options:\n");
2759 printf(" -V Display version number and exit\n");
2760 printf(" -C <configfile> Use an alternate configuration file\n");
2761 printf(" -G <group> Run as a group other than the caller\n");
2762 printf(" -U <user> Run as a user other than the caller\n");
2763 printf(" -c Provide console CLI\n");
2764 printf(" -d Enable extra debugging\n");
2765 #if HAVE_WORKING_FORK
2766 printf(" -f Do not fork\n");
2767 printf(" -F Always fork\n");
2769 printf(" -g Dump core in case of a crash\n");
2770 printf(" -h This help screen\n");
2771 printf(" -i Initialize crypto keys at startup\n");
2772 printf(" -I Enable internal timing if DAHDI timer is available\n");
2773 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2774 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2775 printf(" -m Mute debugging and console output on the console\n");
2776 printf(" -n Disable console colorization\n");
2777 printf(" -p Run as pseudo-realtime thread\n");
2778 printf(" -q Quiet mode (suppress output)\n");
2779 printf(" -r Connect to Asterisk on this machine\n");
2780 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2781 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
2782 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2783 printf(" belong after they are done\n");
2784 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2785 printf(" of output to the CLI\n");
2786 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2787 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2788 printf(" -X Execute includes by default (allows #exec in asterisk.conf)\n");
2789 printf(" -W Adjust terminal colors to compensate for a light background\n");
2794 static void ast_readconfig(void)
2796 struct ast_config *cfg;
2797 struct ast_variable *v;
2798 char *config = DEFAULT_CONFIG_FILE;
2799 char hostname[MAXHOSTNAMELEN] = "";
2800 struct ast_flags config_flags = { 0 };
2802 unsigned int dbdir:1;
2803 unsigned int keydir:1;
2806 if (ast_opt_override_config) {
2807 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
2808 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
2809 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2811 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
2813 /* init with buildtime config */
2814 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2815 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2816 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2817 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
2818 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2819 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2820 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2821 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2822 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2823 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2824 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2825 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2826 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2828 ast_set_default_eid(&ast_eid_default);
2830 /* no asterisk.conf? no problem, use buildtime config! */
2831 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
2835 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2836 if (!strcasecmp(v->name, "astctlpermissions"))
2837 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2838 else if (!strcasecmp(v->name, "astctlowner"))
2839 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2840 else if (!strcasecmp(v->name, "astctlgroup"))
2841 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2842 else if (!strcasecmp(v->name, "astctl"))
2843 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2846 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2847 if (!strcasecmp(v->name, "astetcdir")) {
2848 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2849 } else if (!strcasecmp(v->name, "astspooldir")) {
2850 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2851 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
2852 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2853 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2855 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2856 } else if (!strcasecmp(v->name, "astdbdir")) {
2857 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2859 } else if (!strcasecmp(v->name, "astdatadir")) {
2860 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2862 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2863 } else if (!strcasecmp(v->name, "astkeydir")) {
2864 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2866 } else if (!strcasecmp(v->name, "astlogdir")) {
2867 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2868 } else if (!strcasecmp(v->name, "astagidir")) {
2869 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2870 } else if (!strcasecmp(v->name, "astrundir")) {
2871 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2872 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2873 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2874 } else if (!strcasecmp(v->name, "astmoddir")) {
2875 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2879 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2880 /* verbose level (-v at startup) */
2881 if (!strcasecmp(v->name, "verbose")) {
2882 option_verbose = atoi(v->value);
2883 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2884 } else if (!strcasecmp(v->name, "timestamp")) {
2885 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2886 /* whether or not to support #exec in config files */
2887 } else if (!strcasecmp(v->name, "execincludes")) {
2888 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2889 /* debug level (-d at startup) */
2890 } else if (!strcasecmp(v->name, "debug")) {
2892 if (sscanf(v->value, "%30d", &option_debug) != 1) {
2893 option_debug = ast_true(v->value);
2895 #if HAVE_WORKING_FORK
2896 /* Disable forking (-f at startup) */
2897 } else if (!strcasecmp(v->name, "nofork")) {
2898 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2899 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2900 } else if (!strcasecmp(v->name, "alwaysfork")) {
2901 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2903 /* Run quietly (-q at startup ) */
2904 } else if (!strcasecmp(v->name, "quiet")) {
2905 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2906 /* Run as console (-c at startup, implies nofork) */
2907 } else if (!strcasecmp(v->name, "console")) {
2908 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2909 /* Run with high priority if the O/S permits (-p at startup) */
2910 } else if (!strcasecmp(v->name, "highpriority")) {
2911 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2912 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2913 } else if (!strcasecmp(v->name, "initcrypto")) {
2914 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2915 /* Disable ANSI colors for console (-c at startup) */
2916 } else if (!strcasecmp(v->name, "nocolor")) {
2917 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2918 /* Disable some usage warnings for picky people :p */
2919 } else if (!strcasecmp(v->name, "dontwarn")) {
2920 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2921 /* Dump core in case of crash (-g) */
2922 } else if (!strcasecmp(v->name, "dumpcore")) {
2923 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2924 /* Cache recorded sound files to another directory during recording */
2925 } else if (!strcasecmp(v->name, "cache_record_files")) {
2926 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2927 /* Specify cache directory */
2928 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2929 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2930 /* Build transcode paths via SLINEAR, instead of directly */
2931 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2932 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2933 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2934 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2935 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2936 /* Enable internal timing */
2937 } else if (!strcasecmp(v->name, "internal_timing")) {
2938 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2939 } else if (!strcasecmp(v->name, "maxcalls")) {
2940 if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2941 option_maxcalls = 0;
2943 } else if (!strcasecmp(v->name, "maxload")) {
2946 if (getloadavg(test, 1) == -1) {
2947 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2948 option_maxload = 0.0;
2949 } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2950 option_maxload = 0.0;
2952 /* Set the maximum amount of open files */
2953 } else if (!strcasecmp(v->name, "maxfiles")) {
2954 option_maxfiles = atoi(v->value);
2955 set_ulimit(option_maxfiles);
2956 /* What user to run as */
2957 } else if (!strcasecmp(v->name, "runuser")) {
2958 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
2959 /* What group to run as */
2960 } else if (!strcasecmp(v->name, "rungroup")) {
2961 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
2962 } else if (!strcasecmp(v->name, "systemname")) {
2963 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
2964 } else if (!strcasecmp(v->name, "autosystemname")) {
2965 if (ast_true(v->value)) {
2966 if (!gethostname(hostname, sizeof(hostname) - 1))
2967 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
2969 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2970 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
2972 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2975 } else if (!strcasecmp(v->name, "languageprefix")) {
2976 ast_language_is_prefix = ast_true(v->value);
2977 } else if (!strcasecmp(v->name, "lockmode")) {
2978 if (!strcasecmp(v->value, "lockfile")) {
2979 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2980 } else if (!strcasecmp(v->value, "flock")) {
2981 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
2983 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
2984 "defaulting to 'lockfile'\n", v->value);
2985 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2987 #if defined(HAVE_SYSINFO)
2988 } else if (!strcasecmp(v->name, "minmemfree")) {
2989 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
2990 * if the amount of free memory falls below this watermark */
2991 if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2992 option_minmemfree = 0;
2995 } else if (!strcasecmp(v->name, "entityid")) {
2996 struct ast_eid tmp_eid;
2997 if (!ast_str_to_eid(&tmp_eid, v->value)) {
2998 ast_verbose("Successfully set global EID to '%s'\n", v->value);
2999 ast_eid_default = tmp_eid;
3001 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3002 } else if (!strcasecmp(v->name, "lightbackground")) {
3003 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3004 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3005 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3006 } else if (!strcasecmp(v->name, "hideconnect")) {
3007 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3008 } else if (!strcasecmp(v->name, "lockconfdir")) {
3009 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3012 for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3014 if (sscanf(v->value, "%30f", &version) != 1) {
3015 ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3018 if (!strcasecmp(v->name, "app_set")) {
3019 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3020 } else if (!strcasecmp(v->name, "res_agi")) {
3021 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3022 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3023 ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3026 ast_config_destroy(cfg);
3029 static void *monitor_sig_flags(void *unused)
3032 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3034 ast_poll(&p, 1, -1);
3035 if (sig_flags.need_reload) {
3036 sig_flags.need_reload = 0;
3037 ast_module_reload(NULL);
3039 if (sig_flags.need_quit) {
3040 sig_flags.need_quit = 0;
3041 quit_handler(0, 0, 1, 0);
3043 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3050 static void *canary_thread(void *unused)
3052 struct stat canary_stat;
3055 /* Give the canary time to sing */
3059 stat(canary_filename, &canary_stat);
3061 if (now.tv_sec > canary_stat.st_mtime + 60) {
3062 ast_log(LOG_WARNING, "The canary is no more. He has ceased to be! He's expired and gone to meet his maker! He's a stiff! Bereft of life, he rests in peace. His metabolic processes are now history! He's off the twig! He's kicked the bucket. He's shuffled off his mortal coil, run down the curtain, and joined the bleeding choir invisible!! THIS is an EX-CANARY. (Reducing priority)\n");
3063 ast_set_priority(0);
3067 /* Check the canary once a minute */
3072 /* Used by libc's atexit(3) function */
3073 static void canary_exit(void)
3076 kill(canary_pid, SIGKILL);
3079 static void run_startup_commands(void)
3082 struct ast_config *cfg;
3083 struct ast_flags cfg_flags = { 0 };
3084 struct ast_variable *v;
3086 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3088 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3092 fd = open("/dev/null", O_RDWR);
3094 ast_config_destroy(cfg);
3098 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3099 if (ast_true(v->value))
3100 ast_cli_command(fd, v->name);
3104 ast_config_destroy(cfg);
3107 int main(int argc, char *argv[])
3110 char filename[80] = "";
3111 char hostname[MAXHOSTNAMELEN] = "";
3120 const char *runuser = NULL, *rungroup = NULL;
3121 char *remotesock = NULL;
3122 int moduleresult; /*!< Result from the module load subsystem */
3124 /* Remember original args for restart */
3125 if (argc > ARRAY_LEN(_argv) - 1) {
3126 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
3127 argc = ARRAY_LEN(_argv) - 1;
3129 for (x = 0; x < argc; x++)