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 -- An Open Source Telephony Toolkit
24 * \par Developer Documentation for Asterisk
25 * This is the main developer documentation for Asterisk. It is
26 * generated by running "make progdocs".
27 * \par Additional documentation
29 * \arg \ref ConfigFiles
31 * \section copyright Copyright and author
33 * Copyright (C) 1999 - 2008, Digium, Inc.
34 * Asterisk is a trademark registered by Digium, Inc.
36 * \author Mark Spencer <markster@digium.com>
37 * Also see \ref AstCREDITS
39 * \section license License
40 * See http://www.asterisk.org for more information about
41 * the Asterisk project. Please do not directly contact
42 * any of the maintainers of this project for assistance;
43 * the project provides a web site, mailing lists and IRC
44 * channels for your use.
46 * This program is free software, distributed under the terms of
47 * the GNU General Public License Version 2. See the LICENSE file
48 * at the top of the source tree.
50 * \verbinclude LICENSE
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
64 #include "asterisk/_private.h"
66 #undef sched_setscheduler
75 #include <sys/resource.h>
79 #if defined(HAVE_SYSINFO)
80 #include <sys/sysinfo.h>
83 #include <sys/prctl.h>
85 #include <sys/capability.h>
91 int daemon(int, int); /* defined in libresolv of all places */
92 #include <sys/loadavg.h>
95 #include "asterisk/paths.h" /* we define here the variables so better agree on the prototype */
96 #include "asterisk/network.h"
97 #include "asterisk/cli.h"
98 #include "asterisk/channel.h"
99 #include "asterisk/features.h"
100 #include "asterisk/ulaw.h"
101 #include "asterisk/alaw.h"
102 #include "asterisk/callerid.h"
103 #include "asterisk/image.h"
104 #include "asterisk/tdd.h"
105 #include "asterisk/term.h"
106 #include "asterisk/manager.h"
107 #include "asterisk/cdr.h"
108 #include "asterisk/pbx.h"
109 #include "asterisk/enum.h"
110 #include "asterisk/rtp.h"
111 #include "asterisk/http.h"
112 #include "asterisk/udptl.h"
113 #include "asterisk/app.h"
114 #include "asterisk/lock.h"
115 #include "asterisk/utils.h"
116 #include "asterisk/file.h"
117 #include "asterisk/io.h"
118 #include "editline/histedit.h"
119 #include "asterisk/config.h"
120 #include "asterisk/version.h"
121 #include "asterisk/linkedlists.h"
122 #include "asterisk/devicestate.h"
123 #include "asterisk/module.h"
125 #include "asterisk/doxyref.h" /* Doxygen documentation */
127 #include "../defaults.h"
130 #define AF_LOCAL AF_UNIX
131 #define PF_LOCAL PF_UNIX
134 #define AST_MAX_CONNECTS 128
137 /*! \brief Welcome message when starting a CLI interface */
138 #define WELCOME_MESSAGE \
139 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2008 Digium, Inc. and others.\n" \
140 "Created by Mark Spencer <markster@digium.com>\n" \
141 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
142 "This is free software, with components licensed under the GNU General Public\n" \
143 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
144 "certain conditions. Type 'core show license' for details.\n" \
145 "=========================================================================\n", ast_get_version()) \
147 /*! \defgroup main_options Main Configuration Options
148 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
149 * \arg \ref Config_ast "asterisk.conf"
150 * \note Some of them can be changed in the CLI
154 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
156 int option_verbose; /*!< Verbosity level */
157 int option_debug; /*!< Debug level */
158 double option_maxload; /*!< Max load avg on system */
159 int option_maxcalls; /*!< Max number of active calls */
160 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
161 #if defined(HAVE_SYSINFO)
162 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
167 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
168 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
170 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
171 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
174 int fd; /*!< File descriptor */
175 int p[2]; /*!< Pipe */
176 pthread_t t; /*!< Thread of handler */
177 int mute; /*!< Is the console muted for logs */
182 AST_RWLIST_ENTRY(ast_atexit) list;
185 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
187 struct timeval ast_startuptime;
188 struct timeval ast_lastreloadtime;
190 static History *el_hist;
192 static char *remotehostname;
194 struct console consoles[AST_MAX_CONNECTS];
196 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
198 static int ast_el_add_history(char *);
199 static int ast_el_read_history(char *);
200 static int ast_el_write_history(char *);
203 char config_dir[PATH_MAX];
204 char module_dir[PATH_MAX];
205 char spool_dir[PATH_MAX];
206 char monitor_dir[PATH_MAX];
207 char var_dir[PATH_MAX];
208 char data_dir[PATH_MAX];
209 char log_dir[PATH_MAX];
210 char agi_dir[PATH_MAX];
211 char run_dir[PATH_MAX];
212 char key_dir[PATH_MAX];
214 char config_file[PATH_MAX];
215 char db_path[PATH_MAX];
216 char pid_path[PATH_MAX];
217 char socket_path[PATH_MAX];
218 char run_user[PATH_MAX];
219 char run_group[PATH_MAX];
220 char system_name[128];
223 static struct _cfg_paths cfg_paths;
225 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
226 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
227 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
228 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
229 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
230 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
231 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
232 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
233 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
234 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
235 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
237 const char *ast_config_AST_DB = cfg_paths.db_path;
238 const char *ast_config_AST_PID = cfg_paths.pid_path;
239 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
240 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
241 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
242 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
244 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
245 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
246 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
247 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
249 extern const char *ast_build_hostname;
250 extern const char *ast_build_kernel;
251 extern const char *ast_build_machine;
252 extern const char *ast_build_os;
253 extern const char *ast_build_date;
254 extern const char *ast_build_user;
256 static char *_argv[256];
257 static int shuttingdown;
258 static int restartnow;
259 static pthread_t consolethread = AST_PTHREADT_NULL;
260 static int canary_pid = 0;
261 static char canary_filename[128];
263 static char randompool[256];
265 static int sig_alert_pipe[2] = { -1, -1 };
267 unsigned int need_reload:1;
268 unsigned int need_quit:1;
271 #if !defined(LOW_MEMORY)
272 struct file_version {
273 AST_RWLIST_ENTRY(file_version) list;
278 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
280 void ast_register_file_version(const char *file, const char *version)
282 struct file_version *new;
284 size_t version_length;
286 work = ast_strdupa(version);
287 work = ast_strip(ast_strip_quoted(work, "$", "$"));
288 version_length = strlen(work) + 1;
290 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
294 new->version = (char *) new + sizeof(*new);
295 memcpy(new->version, work, version_length);
296 AST_RWLIST_WRLOCK(&file_versions);
297 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
298 AST_RWLIST_UNLOCK(&file_versions);
301 void ast_unregister_file_version(const char *file)
303 struct file_version *find;
305 AST_RWLIST_WRLOCK(&file_versions);
306 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
307 if (!strcasecmp(find->file, file)) {
308 AST_RWLIST_REMOVE_CURRENT(list);
312 AST_RWLIST_TRAVERSE_SAFE_END;
313 AST_RWLIST_UNLOCK(&file_versions);
319 /*! \brief Find version for given module name */
320 const char *ast_file_version_find(const char *file)
322 struct file_version *iterator;
324 AST_RWLIST_WRLOCK(&file_versions);
325 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, iterator, list) {
326 if (!strcasecmp(iterator->file, file))
329 AST_RWLIST_TRAVERSE_SAFE_END;
330 AST_RWLIST_UNLOCK(&file_versions);
332 return iterator->version;
338 struct thread_list_t {
339 AST_RWLIST_ENTRY(thread_list_t) list;
344 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
346 void ast_register_thread(char *name)
348 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
352 new->id = pthread_self();
353 new->name = name; /* steal the allocated memory for the thread name */
354 AST_RWLIST_WRLOCK(&thread_list);
355 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
356 AST_RWLIST_UNLOCK(&thread_list);
359 void ast_unregister_thread(void *id)
361 struct thread_list_t *x;
363 AST_RWLIST_WRLOCK(&thread_list);
364 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
365 if ((void *) x->id == id) {
366 AST_RWLIST_REMOVE_CURRENT(list);
370 AST_RWLIST_TRAVERSE_SAFE_END;
371 AST_RWLIST_UNLOCK(&thread_list);
378 /*! \brief Give an overview of core settings */
379 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
386 e->command = "core show settings";
387 e->usage = "Usage: core show settings\n"
388 " Show core misc settings";
394 ast_cli(a->fd, "\nPBX Core settings\n");
395 ast_cli(a->fd, "-----------------\n");
396 ast_cli(a->fd, " Version: %s\n", ast_get_version());
398 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
400 ast_cli(a->fd, " Maximum calls: Not set\n");
402 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
404 ast_cli(a->fd, " Maximum open file handles: Not set\n");
405 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
406 ast_cli(a->fd, " Debug level: %d\n", option_debug);
407 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
408 #if defined(HAVE_SYSINFO)
409 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
411 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
412 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
413 ast_cli(a->fd, " Startup time: %s\n", buf);
415 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
416 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
417 ast_cli(a->fd, " Last reload time: %s\n", buf);
419 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);
420 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
421 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
422 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
423 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
424 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
425 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
426 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
427 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
429 ast_cli(a->fd, "\n* Subsystems\n");
430 ast_cli(a->fd, " -------------\n");
431 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
432 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
433 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
434 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
436 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
438 ast_cli(a->fd, "\n* Directories\n");
439 ast_cli(a->fd, " -------------\n");
440 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
441 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
442 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
443 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
444 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
445 ast_cli(a->fd, "\n\n");
449 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
452 struct thread_list_t *cur;
455 e->command = "core show threads";
457 "Usage: core show threads\n"
458 " List threads currently active in the system.\n";
464 AST_RWLIST_RDLOCK(&thread_list);
465 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
466 ast_cli(a->fd, "%p %s\n", (void *)cur->id, cur->name);
469 AST_RWLIST_UNLOCK(&thread_list);
470 ast_cli(a->fd, "%d threads listed.\n", count);
474 #if defined(HAVE_SYSINFO)
475 /*! \brief Give an overview of system statistics */
476 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
478 struct sysinfo sys_info;
481 e->command = "core show sysinfo";
483 "Usage: core show sysinfo\n"
484 " List current system information.\n";
489 if (sysinfo(&sys_info)) {
490 ast_cli(a->fd, "FAILED to retrieve system information\n\n");
493 ast_cli(a->fd, "\nSystem Statistics\n");
494 ast_cli(a->fd, "-----------------\n");
495 ast_cli(a->fd, " System Uptime: %ld hours\n", sys_info.uptime/3600);
496 ast_cli(a->fd, " Total RAM: %ld KiB\n", (sys_info.totalram / sys_info.mem_unit)/1024);
497 ast_cli(a->fd, " Free RAM: %ld KiB\n", (sys_info.freeram / sys_info.mem_unit)/1024);
498 ast_cli(a->fd, " Buffer RAM: %ld KiB\n", (sys_info.bufferram / sys_info.mem_unit)/1024);
499 ast_cli(a->fd, " Total Swap Space: %ld KiB\n", (sys_info.totalswap / sys_info.mem_unit)/1024);
500 ast_cli(a->fd, " Free Swap Space: %ld KiB\n\n", (sys_info.freeswap / sys_info.mem_unit)/1024);
501 ast_cli(a->fd, " Number of Processes: %d \n\n", sys_info.procs);
506 struct profile_entry {
508 uint64_t scale; /* if non-zero, values are scaled by this */
514 struct profile_data {
517 struct profile_entry e[0];
520 static struct profile_data *prof_data;
522 /*! \brief allocates a counter with a given name and scale.
523 * \return Returns the identifier of the counter.
525 int ast_add_profile(const char *name, uint64_t scale)
527 int l = sizeof(struct profile_data);
528 int n = 10; /* default entries */
530 if (prof_data == NULL) {
531 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
532 if (prof_data == NULL)
534 prof_data->entries = 0;
535 prof_data->max_size = n;
537 if (prof_data->entries >= prof_data->max_size) {
539 n = prof_data->max_size + 20;
540 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
544 prof_data->max_size = n;
546 n = prof_data->entries++;
547 prof_data->e[n].name = ast_strdup(name);
548 prof_data->e[n].value = 0;
549 prof_data->e[n].events = 0;
550 prof_data->e[n].mark = 0;
551 prof_data->e[n].scale = scale;
555 int64_t ast_profile(int i, int64_t delta)
557 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
559 if (prof_data->e[i].scale > 1)
560 delta /= prof_data->e[i].scale;
561 prof_data->e[i].value += delta;
562 prof_data->e[i].events++;
563 return prof_data->e[i].value;
566 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
567 #if defined(__FreeBSD__)
568 #include <machine/cpufunc.h>
570 static __inline uint64_t
575 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
579 #else /* supply a dummy function on other platforms */
580 static __inline uint64_t
587 int64_t ast_mark(int i, int startstop)
589 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
592 prof_data->e[i].mark = rdtsc();
594 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
595 if (prof_data->e[i].scale > 1)
596 prof_data->e[i].mark /= prof_data->e[i].scale;
597 prof_data->e[i].value += prof_data->e[i].mark;
598 prof_data->e[i].events++;
600 return prof_data->e[i].mark;
603 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
604 max = prof_data->entries;\
605 if (a->argc > 3) { /* specific entries */ \
606 if (isdigit(a->argv[3][0])) { \
607 min = atoi(a->argv[3]); \
608 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
609 max = atoi(a->argv[4]); \
611 search = a->argv[3]; \
613 if (max > prof_data->entries) \
614 max = prof_data->entries;
616 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
622 e->command = "core show profile";
623 e->usage = "Usage: core show profile\n"
624 " show profile information";
630 if (prof_data == NULL)
633 DEFINE_PROFILE_MIN_MAX_VALUES;
634 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
635 prof_data->entries, prof_data->max_size);
636 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
637 "Value", "Average", "Name");
638 for (i = min; i < max; i++) {
639 struct profile_entry *e = &prof_data->e[i];
640 if (!search || strstr(prof_data->e[i].name, search))
641 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
644 (long)e->events, (long long)e->value,
645 (long long)(e->events ? e->value / e->events : e->value),
651 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
657 e->command = "core clear profile";
658 e->usage = "Usage: core clear profile\n"
659 " clear profile information";
665 if (prof_data == NULL)
668 DEFINE_PROFILE_MIN_MAX_VALUES;
669 for (i= min; i < max; i++) {
670 if (!search || strstr(prof_data->e[i].name, search)) {
671 prof_data->e[i].value = 0;
672 prof_data->e[i].events = 0;
677 #undef DEFINE_PROFILE_MIN_MAX_VALUES
679 /*! \brief CLI command to list module versions */
680 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
682 #define FORMAT "%-25.25s %-40.40s\n"
683 struct file_version *iterator;
689 int matchlen, which = 0;
690 struct file_version *find;
694 e->command = "core show file version [like]";
696 "Usage: core show file version [like <pattern>]\n"
697 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
698 " Optional regular expression pattern is used to filter the file list.\n";
701 matchlen = strlen(a->word);
704 AST_RWLIST_RDLOCK(&file_versions);
705 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
706 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
707 ret = ast_strdup(find->file);
711 AST_RWLIST_UNLOCK(&file_versions);
718 if (!strcasecmp(a->argv[4], "like")) {
719 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
720 return CLI_SHOWUSAGE;
723 return CLI_SHOWUSAGE;
731 return CLI_SHOWUSAGE;
734 ast_cli(a->fd, FORMAT, "File", "Revision");
735 ast_cli(a->fd, FORMAT, "----", "--------");
736 AST_RWLIST_RDLOCK(&file_versions);
737 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
738 if (havename && strcasecmp(iterator->file, a->argv[4]))
741 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
744 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
749 AST_RWLIST_UNLOCK(&file_versions);
751 ast_cli(a->fd, "%d files listed.\n", count_files);
761 #endif /* ! LOW_MEMORY */
763 int ast_register_atexit(void (*func)(void))
765 struct ast_atexit *ae;
767 if (!(ae = ast_calloc(1, sizeof(*ae))))
772 ast_unregister_atexit(func);
774 AST_RWLIST_WRLOCK(&atexits);
775 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
776 AST_RWLIST_UNLOCK(&atexits);
781 void ast_unregister_atexit(void (*func)(void))
783 struct ast_atexit *ae = NULL;
785 AST_RWLIST_WRLOCK(&atexits);
786 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
787 if (ae->func == func) {
788 AST_RWLIST_REMOVE_CURRENT(list);
792 AST_RWLIST_TRAVERSE_SAFE_END;
793 AST_RWLIST_UNLOCK(&atexits);
799 static int fdprint(int fd, const char *s)
801 return write(fd, s, strlen(s) + 1);
804 /*! \brief NULL handler so we can collect the child exit status */
805 static void null_sig_handler(int signal)
810 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
811 /*! \brief Keep track of how many threads are currently trying to wait*() on
813 static unsigned int safe_system_level = 0;
814 static void *safe_system_prev_handler;
816 void ast_replace_sigchld(void)
820 ast_mutex_lock(&safe_system_lock);
821 level = safe_system_level++;
823 /* only replace the handler if it has not already been done */
825 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
827 ast_mutex_unlock(&safe_system_lock);
830 void ast_unreplace_sigchld(void)
834 ast_mutex_lock(&safe_system_lock);
835 level = --safe_system_level;
837 /* only restore the handler if we are the last one */
839 signal(SIGCHLD, safe_system_prev_handler);
841 ast_mutex_unlock(&safe_system_lock);
844 int ast_safe_system(const char *s)
847 #ifdef HAVE_WORKING_FORK
851 struct rusage rusage;
854 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
855 ast_replace_sigchld();
857 #ifdef HAVE_WORKING_FORK
864 #ifdef HAVE_WORKING_FORK
865 if (ast_opt_high_priority)
867 /* Close file descriptors and launch system command */
868 for (x = STDERR_FILENO + 1; x < 4096; x++)
871 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
873 } else if (pid > 0) {
875 res = wait4(pid, &status, 0, &rusage);
877 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
879 } else if (errno != EINTR)
883 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
887 ast_unreplace_sigchld();
896 * \brief mute or unmute a console from logging
898 void ast_console_toggle_mute(int fd, int silent) {
900 for (x = 0;x < AST_MAX_CONNECTS; x++) {
901 if (fd == consoles[x].fd) {
902 if (consoles[x].mute) {
903 consoles[x].mute = 0;
905 ast_cli(fd, "Console is not muted anymore.\n");
907 consoles[x].mute = 1;
909 ast_cli(fd, "Console is muted.\n");
914 ast_cli(fd, "Couldn't find remote console.\n");
918 * \brief log the string to all attached console clients
920 static void ast_network_puts_mutable(const char *string)
923 for (x = 0;x < AST_MAX_CONNECTS; x++) {
924 if (consoles[x].mute)
926 if (consoles[x].fd > -1)
927 fdprint(consoles[x].p[1], string);
932 * \brief log the string to the console, and all attached
935 void ast_console_puts_mutable(const char *string)
937 fputs(string, stdout);
939 ast_network_puts_mutable(string);
943 * \brief write the string to all attached console clients
945 static void ast_network_puts(const char *string)
948 for (x = 0; x < AST_MAX_CONNECTS; x++) {
949 if (consoles[x].fd > -1)
950 fdprint(consoles[x].p[1], string);
955 * write the string to the console, and all attached
958 void ast_console_puts(const char *string)
960 fputs(string, stdout);
962 ast_network_puts(string);
965 static void network_verboser(const char *s)
967 ast_network_puts_mutable(s);
970 static pthread_t lthread;
972 static void *netconsole(void *vconsole)
974 struct console *con = vconsole;
975 char hostname[MAXHOSTNAMELEN] = "";
978 struct pollfd fds[2];
980 if (gethostname(hostname, sizeof(hostname)-1))
981 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
982 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
983 fdprint(con->fd, tmp);
986 fds[0].events = POLLIN;
988 fds[1].fd = con->p[0];
989 fds[1].events = POLLIN;
992 res = poll(fds, 2, -1);
995 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
998 if (fds[0].revents) {
999 res = read(con->fd, tmp, sizeof(tmp));
1004 ast_cli_command_multiple(con->fd, res, tmp);
1006 if (fds[1].revents) {
1007 res = read(con->p[0], tmp, sizeof(tmp));
1009 ast_log(LOG_ERROR, "read returned %d\n", res);
1012 res = write(con->fd, tmp, res);
1017 ast_verb(3, "Remote UNIX connection disconnected\n");
1026 static void *listener(void *unused)
1028 struct sockaddr_un sunaddr;
1033 struct pollfd fds[1];
1037 fds[0].fd = ast_socket;
1038 fds[0].events = POLLIN;
1039 s = poll(fds, 1, -1);
1040 pthread_testcancel();
1043 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1046 len = sizeof(sunaddr);
1047 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1050 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1052 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1053 if (consoles[x].fd < 0) {
1054 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1055 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1056 consoles[x].fd = -1;
1057 fdprint(s, "Server failed to create pipe\n");
1061 flags = fcntl(consoles[x].p[1], F_GETFL);
1062 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1064 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1065 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1066 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1067 close(consoles[x].p[0]);
1068 close(consoles[x].p[1]);
1069 consoles[x].fd = -1;
1070 fdprint(s, "Server failed to spawn thread\n");
1076 if (x >= AST_MAX_CONNECTS) {
1077 fdprint(s, "No more connections allowed\n");
1078 ast_log(LOG_WARNING, "No more connections allowed\n");
1080 } else if (consoles[x].fd > -1)
1081 ast_verb(3, "Remote UNIX connection\n");
1087 static int ast_makesocket(void)
1089 struct sockaddr_un sunaddr;
1095 for (x = 0; x < AST_MAX_CONNECTS; x++)
1096 consoles[x].fd = -1;
1097 unlink(ast_config_AST_SOCKET);
1098 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1099 if (ast_socket < 0) {
1100 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1103 memset(&sunaddr, 0, sizeof(sunaddr));
1104 sunaddr.sun_family = AF_LOCAL;
1105 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1106 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1108 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1113 res = listen(ast_socket, 2);
1115 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1120 ast_register_verbose(network_verboser);
1121 ast_pthread_create_background(<hread, NULL, listener, NULL);
1123 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1125 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1126 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1131 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1133 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1134 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1139 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1140 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1142 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1145 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
1147 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1148 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1154 static int ast_tryconnect(void)
1156 struct sockaddr_un sunaddr;
1158 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1159 if (ast_consock < 0) {
1160 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1163 memset(&sunaddr, 0, sizeof(sunaddr));
1164 sunaddr.sun_family = AF_LOCAL;
1165 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1166 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1175 /*! \brief Urgent handler
1177 Called by soft_hangup to interrupt the poll, read, or other
1178 system call. We don't actually need to do anything though.
1179 Remember: Cannot EVER ast_log from within a signal handler
1181 static void urg_handler(int num)
1183 signal(num, urg_handler);
1187 static void hup_handler(int num)
1190 if (option_verbose > 1)
1191 printf("Received HUP signal -- Reloading configs\n");
1193 execvp(_argv[0], _argv);
1194 sig_flags.need_reload = 1;
1195 if (sig_alert_pipe[1] != -1)
1196 write(sig_alert_pipe[1], &a, sizeof(a));
1197 signal(num, hup_handler);
1200 static void child_handler(int sig)
1202 /* Must not ever ast_log or ast_verbose within signal handler */
1206 * Reap all dead children -- not just one
1208 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1210 if (n == 0 && option_debug)
1211 printf("Huh? Child handler, but nobody there?\n");
1212 signal(sig, child_handler);
1215 /*! \brief Set maximum open files */
1216 static void set_ulimit(int value)
1218 struct rlimit l = {0, 0};
1221 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1228 if (setrlimit(RLIMIT_NOFILE, &l)) {
1229 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1233 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1238 /*! \brief Set an X-term or screen title */
1239 static void set_title(char *text)
1241 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1242 fprintf(stdout, "\033]2;%s\007", text);
1245 static void set_icon(char *text)
1247 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1248 fprintf(stdout, "\033]1;%s\007", text);
1251 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1252 else. If your PBX has heavy activity on it, this is a good thing. */
1253 int ast_set_priority(int pri)
1255 struct sched_param sched;
1256 memset(&sched, 0, sizeof(sched));
1259 sched.sched_priority = 10;
1260 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1261 ast_log(LOG_WARNING, "Unable to set high priority\n");
1265 ast_verbose("Set to realtime thread\n");
1267 sched.sched_priority = 0;
1268 /* According to the manpage, these parameters can never fail. */
1269 sched_setscheduler(0, SCHED_OTHER, &sched);
1273 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1274 ast_log(LOG_WARNING, "Unable to set high priority\n");
1278 ast_verbose("Set to high priority\n");
1280 /* According to the manpage, these parameters can never fail. */
1281 setpriority(PRIO_PROCESS, 0, 0);
1287 static void ast_run_atexits(void)
1289 struct ast_atexit *ae;
1290 AST_RWLIST_RDLOCK(&atexits);
1291 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1295 AST_RWLIST_UNLOCK(&atexits);
1298 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1300 char filename[80] = "";
1303 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1304 ast_cdr_engine_term();
1308 /* Begin shutdown routine, hanging up active channels */
1309 ast_begin_shutdown(1);
1310 if (option_verbose && ast_opt_console)
1311 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1315 /* Wait up to 15 seconds for all channels to go away */
1318 if (!ast_active_channels())
1322 /* Sleep 1/10 of a second */
1327 ast_begin_shutdown(0);
1328 if (option_verbose && ast_opt_console)
1329 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1331 if (!ast_active_channels())
1339 if (!shuttingdown) {
1340 if (option_verbose && ast_opt_console)
1341 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1346 ast_module_shutdown();
1348 if (ast_opt_console || ast_opt_remote) {
1350 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1351 if (!ast_strlen_zero(filename))
1352 ast_el_write_history(filename);
1355 if (el_hist != NULL)
1356 history_end(el_hist);
1359 ast_verbose("Executing last minute cleanups\n");
1361 /* Called on exit */
1362 if (option_verbose && ast_opt_console)
1363 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1364 ast_debug(1, "Asterisk ending (%d).\n", num);
1365 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1366 if (ast_socket > -1) {
1367 pthread_cancel(lthread);
1370 unlink(ast_config_AST_SOCKET);
1372 if (ast_consock > -1)
1374 if (!ast_opt_remote)
1375 unlink(ast_config_AST_PID);
1376 printf(term_quit());
1378 if (option_verbose || ast_opt_console)
1379 ast_verbose("Preparing for Asterisk restart...\n");
1380 /* Mark all FD's for closing on exec */
1381 for (x=3; x < 32768; x++) {
1382 fcntl(x, F_SETFD, FD_CLOEXEC);
1384 if (option_verbose || ast_opt_console)
1385 ast_verbose("Asterisk is now restarting...\n");
1391 /* If there is a consolethread running send it a SIGHUP
1392 so it can execvp, otherwise we can do it ourselves */
1393 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1394 pthread_kill(consolethread, SIGHUP);
1395 /* Give the signal handler some time to complete */
1398 execvp(_argv[0], _argv);
1407 static void __quit_handler(int num)
1410 sig_flags.need_quit = 1;
1411 if (sig_alert_pipe[1] != -1)
1412 write(sig_alert_pipe[1], &a, sizeof(a));
1413 /* There is no need to restore the signal handler here, since the app
1414 * is going to exit */
1417 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1420 if (!strncmp(s, cmp, strlen(cmp))) {
1421 c = s + strlen(cmp);
1422 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1428 static void console_verboser(const char *s)
1431 const char *c = NULL;
1433 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1434 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1435 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1436 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1444 /* Wake up a poll()ing console */
1445 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1446 pthread_kill(consolethread, SIGURG);
1449 static int ast_all_zeros(char *s)
1459 static void consolehandler(char *s)
1464 /* Called when readline data is available */
1465 if (!ast_all_zeros(s))
1466 ast_el_add_history(s);
1467 /* The real handler for bang */
1470 ast_safe_system(s+1);
1472 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1474 ast_cli_command(STDOUT_FILENO, s);
1477 static int remoteconsolehandler(char *s)
1481 /* Called when readline data is available */
1482 if (!ast_all_zeros(s))
1483 ast_el_add_history(s);
1484 /* The real handler for bang */
1487 ast_safe_system(s+1);
1489 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1492 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1493 (s[4] == '\0' || isspace(s[4]))) {
1494 quit_handler(0, 0, 0, 0);
1501 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1505 e->command = "core show version";
1507 "Usage: core show version\n"
1508 " Shows Asterisk version information.\n";
1515 return CLI_SHOWUSAGE;
1516 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1517 ast_get_version(), ast_build_user, ast_build_hostname,
1518 ast_build_machine, ast_build_os, ast_build_date);
1523 static int handle_quit(int fd, int argc, char *argv[])
1526 return RESULT_SHOWUSAGE;
1527 quit_handler(0, 0, 1, 0);
1528 return RESULT_SUCCESS;
1532 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1536 e->command = "core stop now";
1538 "Usage: core stop now\n"
1539 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1545 if (a->argc != e->args)
1546 return CLI_SHOWUSAGE;
1547 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1551 static char *handle_stop_now_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1553 char *res = handle_stop_now(e, cmd, a);
1554 if (cmd == CLI_INIT)
1555 e->command = "stop now";
1559 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1563 e->command = "core stop gracefully";
1565 "Usage: core stop gracefully\n"
1566 " Causes Asterisk to not accept new calls, and exit when all\n"
1567 " active calls have terminated normally.\n";
1573 if (a->argc != e->args)
1574 return CLI_SHOWUSAGE;
1575 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1579 static char *handle_stop_gracefully_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1581 char *res = handle_stop_gracefully(e, cmd, a);
1582 if (cmd == CLI_INIT)
1583 e->command = "stop gracefully";
1587 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1591 e->command = "core stop when convenient";
1593 "Usage: core stop when convenient\n"
1594 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1600 if (a->argc != e->args)
1601 return CLI_SHOWUSAGE;
1602 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
1603 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1607 static char *handle_stop_when_convenient_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1609 char *res = handle_stop_when_convenient(e, cmd, a);
1610 if (cmd == CLI_INIT)
1611 e->command = "stop when convenient";
1615 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1619 e->command = "core restart now";
1621 "Usage: core restart now\n"
1622 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1629 if (a->argc != e->args)
1630 return CLI_SHOWUSAGE;
1631 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1635 static char *handle_restart_now_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1637 char *res = handle_restart_now(e, cmd, a);
1638 if (cmd == CLI_INIT)
1639 e->command = "restart now";
1643 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1647 e->command = "core restart gracefully";
1649 "Usage: core restart gracefully\n"
1650 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1651 " restart when all active calls have ended.\n";
1657 if (a->argc != e->args)
1658 return CLI_SHOWUSAGE;
1659 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1663 static char *handle_restart_gracefully_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1665 char *res = handle_restart_gracefully(e, cmd, a);
1666 if (cmd == CLI_INIT)
1667 e->command = "restart gracefully";
1671 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1675 e->command = "core restart when convenient";
1677 "Usage: core restart when convenient\n"
1678 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1684 if (a->argc != e->args)
1685 return CLI_SHOWUSAGE;
1686 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
1687 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1691 static char *handle_restart_when_convenient_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1693 char *res = handle_restart_when_convenient(e, cmd, a);
1694 if (cmd == CLI_INIT)
1695 e->command = "restart when convenient";
1699 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1703 e->command = "core abort shutdown";
1705 "Usage: core abort shutdown\n"
1706 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1707 " call operations.\n";
1713 if (a->argc != e->args)
1714 return CLI_SHOWUSAGE;
1715 ast_cancel_shutdown();
1720 static char *handle_abort_shutdown_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1722 char *res = handle_abort_shutdown(e, cmd, a);
1723 if (cmd == CLI_INIT)
1724 e->command = "abort shutdown";
1728 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1734 "Usage: !<command>\n"
1735 " Executes a given shell command\n";
1743 static const char warranty_lines[] = {
1747 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
1748 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
1749 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
1750 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
1751 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
1752 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
1753 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
1754 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
1755 "REPAIR OR CORRECTION.\n"
1757 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
1758 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
1759 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
1760 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
1761 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
1762 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
1763 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
1764 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
1765 "POSSIBILITY OF SUCH DAMAGES.\n"
1768 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1772 e->command = "core show warranty";
1774 "Usage: core show warranty\n"
1775 " Shows the warranty (if any) for this copy of Asterisk.\n";
1781 ast_cli(a->fd, warranty_lines);
1786 static const char license_lines[] = {
1788 "This program is free software; you can redistribute it and/or modify\n"
1789 "it under the terms of the GNU General Public License version 2 as\n"
1790 "published by the Free Software Foundation.\n"
1792 "This program also contains components licensed under other licenses.\n"
1795 "This program is distributed in the hope that it will be useful,\n"
1796 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1797 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1798 "GNU General Public License for more details.\n"
1800 "You should have received a copy of the GNU General Public License\n"
1801 "along with this program; if not, write to the Free Software\n"
1802 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
1805 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1809 e->command = "core show license";
1811 "Usage: core show license\n"
1812 " Shows the license(s) for this copy of Asterisk.\n";
1818 ast_cli(a->fd, license_lines);
1823 #define ASTERISK_PROMPT "*CLI> "
1825 #define ASTERISK_PROMPT2 "%s*CLI> "
1827 /* deprecated cli entries */
1828 static struct ast_cli_entry cli_abort_shutdown_deprecated = AST_CLI_DEFINE(handle_abort_shutdown_deprecated, "Cancel a running shutdown.");
1829 static struct ast_cli_entry cli_stop_now_deprecated = AST_CLI_DEFINE(handle_stop_now_deprecated, "Shut down Asterisk immediately.");
1830 static struct ast_cli_entry cli_stop_gracefully_deprecated = AST_CLI_DEFINE(handle_stop_gracefully_deprecated, "Gracefully shut down Asterisk.");
1831 static struct ast_cli_entry cli_stop_when_convenient_deprecated = AST_CLI_DEFINE(handle_stop_when_convenient_deprecated, "Shut down Asterisk at empty call volume.");
1832 static struct ast_cli_entry cli_restart_now_deprecated = AST_CLI_DEFINE(handle_restart_now_deprecated, "Restart Asterisk immediately.");
1833 static struct ast_cli_entry cli_restart_gracefully_deprecated = AST_CLI_DEFINE(handle_restart_gracefully_deprecated, "Restart Asterisk gracefully.");
1834 static struct ast_cli_entry cli_restart_when_convenient_deprecated = AST_CLI_DEFINE(handle_restart_when_convenient_deprecated, "Restart Asterisk at empty call volume.");
1835 /* end deprecated cli entries */
1837 static struct ast_cli_entry cli_asterisk[] = {
1838 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown", .deprecate_cmd = &cli_abort_shutdown_deprecated),
1839 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately", .deprecate_cmd = &cli_stop_now_deprecated),
1840 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk", .deprecate_cmd = &cli_stop_gracefully_deprecated),
1841 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume", .deprecate_cmd = &cli_stop_when_convenient_deprecated),
1842 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately", .deprecate_cmd = &cli_restart_now_deprecated),
1843 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully", .deprecate_cmd = &cli_restart_gracefully_deprecated),
1844 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume", .deprecate_cmd = &cli_restart_when_convenient_deprecated),
1845 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
1846 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
1847 AST_CLI_DEFINE(handle_version, "Display version info"),
1848 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
1849 #if !defined(LOW_MEMORY)
1850 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
1851 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
1852 #if defined(HAVE_SYSINFO)
1853 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
1855 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
1856 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
1857 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
1858 #endif /* ! LOW_MEMORY */
1861 static int ast_el_read_char(EditLine *el, char *cp)
1865 struct pollfd fds[2];
1868 #define EL_BUF_SIZE 512
1869 char buf[EL_BUF_SIZE];
1873 fds[0].fd = ast_consock;
1874 fds[0].events = POLLIN;
1875 if (!ast_opt_exec) {
1876 fds[1].fd = STDIN_FILENO;
1877 fds[1].events = POLLIN;
1880 res = poll(fds, max, -1);
1884 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1888 if (!ast_opt_exec && fds[1].revents) {
1889 num_read = read(STDIN_FILENO, cp, 1);
1895 if (fds[0].revents) {
1896 res = read(ast_consock, buf, sizeof(buf) - 1);
1897 /* if the remote side disappears exit */
1899 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1900 if (!ast_opt_reconnect) {
1901 quit_handler(0, 0, 0, 0);
1904 int reconnects_per_second = 20;
1905 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1906 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
1907 if (ast_tryconnect()) {
1908 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1909 printf(term_quit());
1912 fdprint(ast_consock, "logger mute silent");
1914 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
1917 usleep(1000000 / reconnects_per_second);
1919 if (tries >= 30 * reconnects_per_second) {
1920 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1921 quit_handler(0, 0, 0, 0);
1928 if (!ast_opt_exec && !lastpos)
1929 write(STDOUT_FILENO, "\r", 1);
1930 write(STDOUT_FILENO, buf, res);
1931 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
1943 static char *cli_prompt(EditLine *el)
1945 static char prompt[200];
1950 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1951 char *t = pfmt, *p = prompt;
1952 memset(prompt, 0, sizeof(prompt));
1953 while (*t != '\0' && *p < sizeof(prompt)) {
1955 char hostname[MAXHOSTNAMELEN]="";
1957 struct timeval ts = ast_tvnow();
1958 struct ast_tm tm = { 0, };
1962 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1966 case 'C': /* color */
1968 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1969 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1971 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1972 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1976 /* If the color has been reset correctly, then there's no need to reset it later */
1977 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
1979 case 'd': /* date */
1980 if (ast_localtime(&ts, &tm, NULL))
1981 ast_strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1983 case 'h': /* hostname */
1984 if (!gethostname(hostname, sizeof(hostname) - 1))
1985 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1987 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1989 case 'H': /* short hostname */
1990 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1991 for (i = 0; i < sizeof(hostname); i++) {
1992 if (hostname[i] == '.') {
1997 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1999 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
2002 case 'l': /* load avg */
2004 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
2005 float avg1, avg2, avg3;
2006 int actproc, totproc, npid, which;
2007 fscanf(LOADAVG, "%f %f %f %d/%d %d",
2008 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
2009 if (sscanf(t, "%d", &which) == 1) {
2012 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
2015 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
2018 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
2021 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
2024 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
2031 case 's': /* Asterisk system name (from asterisk.conf) */
2032 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
2034 case 't': /* time */
2035 if (ast_localtime(&ts, &tm, NULL))
2036 ast_strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
2038 case '#': /* process console or remote? */
2039 if (!ast_opt_remote)
2040 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
2042 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
2044 case '%': /* literal % */
2045 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
2047 case '\0': /* % is last character - prevent bug */
2061 /* Force colors back to normal at end */
2062 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
2063 if (strlen(term_code) > sizeof(prompt) - strlen(prompt))
2064 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
2066 strncat(p, term_code, sizeof(term_code));
2068 } else if (remotehostname)
2069 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
2071 ast_copy_string(prompt, ASTERISK_PROMPT, sizeof(prompt));
2076 static char **ast_el_strtoarr(char *buf)
2078 char **match_list = NULL, **match_list_tmp, *retstr;
2079 size_t match_list_len;
2083 while ( (retstr = strsep(&buf, " ")) != NULL) {
2085 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2087 if (matches + 1 >= match_list_len) {
2088 match_list_len <<= 1;
2089 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2090 match_list = match_list_tmp;
2093 ast_free(match_list);
2094 return (char **) NULL;
2098 match_list[matches++] = ast_strdup(retstr);
2102 return (char **) NULL;
2104 if (matches >= match_list_len) {
2105 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2106 match_list = match_list_tmp;
2109 ast_free(match_list);
2110 return (char **) NULL;
2114 match_list[matches] = (char *) NULL;
2119 static int ast_el_sort_compare(const void *i1, const void *i2)
2123 s1 = ((char **)i1)[0];
2124 s2 = ((char **)i2)[0];
2126 return strcasecmp(s1, s2);
2129 static int ast_cli_display_match_list(char **matches, int len, int max)
2131 int i, idx, limit, count;
2132 int screenwidth = 0;
2133 int numoutput = 0, numoutputline = 0;
2135 screenwidth = ast_get_termcols(STDOUT_FILENO);
2137 /* find out how many entries can be put on one line, with two spaces between strings */
2138 limit = screenwidth / (max + 2);
2142 /* how many lines of output */
2143 count = len / limit;
2144 if (count * limit < len)
2149 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2151 for (; count > 0; count--) {
2153 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2155 /* Don't print dupes */
2156 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2158 ast_free(matches[idx]);
2159 matches[idx] = NULL;
2165 fprintf(stdout, "%-*s ", max, matches[idx]);
2166 ast_free(matches[idx]);
2167 matches[idx] = NULL;
2169 if (numoutputline > 0)
2170 fprintf(stdout, "\n");
2177 static char *cli_complete(EditLine *el, int ch)
2183 int retval = CC_ERROR;
2187 LineInfo *lf = (LineInfo *)el_line(el);
2189 *(char *)lf->cursor = '\0';
2190 ptr = (char *)lf->cursor;
2192 while (ptr > lf->buffer) {
2193 if (isspace(*ptr)) {
2201 len = lf->cursor - ptr;
2203 if (ast_opt_remote) {
2204 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2205 fdprint(ast_consock, buf);
2206 res = read(ast_consock, buf, sizeof(buf));
2208 nummatches = atoi(buf);
2210 if (nummatches > 0) {
2212 int mlen = 0, maxmbuf = 2048;
2213 /* Start with a 2048 byte buffer */
2214 if (!(mbuf = ast_malloc(maxmbuf)))
2215 return (char *)(CC_ERROR);
2216 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2217 fdprint(ast_consock, buf);
2220 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2221 if (mlen + 1024 > maxmbuf) {
2222 /* Every step increment buffer 1024 bytes */
2224 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2225 return (char *)(CC_ERROR);
2227 /* Only read 1024 bytes at a time */
2228 res = read(ast_consock, mbuf + mlen, 1024);
2234 matches = ast_el_strtoarr(mbuf);
2237 matches = (char **) NULL;
2239 char **p, *oldbuf=NULL;
2241 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2242 for (p = matches; p && *p; p++) {
2243 if (!oldbuf || strcmp(*p,oldbuf))
2251 int matches_num, maxlen, match_len;
2253 if (matches[0][0] != '\0') {
2254 el_deletestr(el, (int) len);
2255 el_insertstr(el, matches[0]);
2256 retval = CC_REFRESH;
2259 if (nummatches == 1) {
2260 /* Found an exact match */
2261 el_insertstr(el, " ");
2262 retval = CC_REFRESH;
2264 /* Must be more than one match */
2265 for (i = 1, maxlen = 0; matches[i]; i++) {
2266 match_len = strlen(matches[i]);
2267 if (match_len > maxlen)
2270 matches_num = i - 1;
2271 if (matches_num >1) {
2272 fprintf(stdout, "\n");
2273 ast_cli_display_match_list(matches, nummatches, maxlen);
2274 retval = CC_REDISPLAY;
2276 el_insertstr(el," ");
2277 retval = CC_REFRESH;
2280 for (i = 0; matches[i]; i++)
2281 ast_free(matches[i]);
2285 return (char *)(long)retval;
2288 static int ast_el_initialize(void)
2291 char *editor = getenv("AST_EDITOR");
2295 if (el_hist != NULL)
2296 history_end(el_hist);
2298 el = el_init("asterisk", stdin, stdout, stderr);
2299 el_set(el, EL_PROMPT, cli_prompt);
2301 el_set(el, EL_EDITMODE, 1);
2302 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2303 el_hist = history_init();
2304 if (!el || !el_hist)
2307 /* setup history with 100 entries */
2308 history(el_hist, &ev, H_SETSIZE, 100);
2310 el_set(el, EL_HIST, history, el_hist);
2312 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2313 /* Bind <tab> to command completion */
2314 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2315 /* Bind ? to command completion */
2316 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2317 /* Bind ^D to redisplay */
2318 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2323 static int ast_el_add_history(char *buf)
2327 if (el_hist == NULL || el == NULL)
2328 ast_el_initialize();
2329 if (strlen(buf) > 256)
2331 return (history(el_hist, &ev, H_ENTER, buf));
2334 static int ast_el_write_history(char *filename)
2338 if (el_hist == NULL || el == NULL)
2339 ast_el_initialize();
2341 return (history(el_hist, &ev, H_SAVE, filename));
2344 static int ast_el_read_history(char *filename)
2350 if (el_hist == NULL || el == NULL)
2351 ast_el_initialize();
2353 if ((f = fopen(filename, "r")) == NULL)
2357 fgets(buf, sizeof(buf), f);
2358 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2360 if (ast_all_zeros(buf))
2362 if ((ret = ast_el_add_history(buf)) == -1)
2370 static void ast_remotecontrol(char * data)
2374 char filename[80] = "";
2380 char *stringp = NULL;
2385 read(ast_consock, buf, sizeof(buf));
2387 write(ast_consock, data, strlen(data) + 1);
2389 hostname = strsep(&stringp, "/");
2390 cpid = strsep(&stringp, "/");
2391 version = strsep(&stringp, "\n");
2393 version = "<Version Unknown>";
2395 strsep(&stringp, ".");
2401 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2402 fdprint(ast_consock, tmp);
2403 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2404 fdprint(ast_consock, tmp);
2406 fdprint(ast_consock, "logger mute silent");
2408 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2410 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2411 remotehostname = hostname;
2413 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2414 if (el_hist == NULL || el == NULL)
2415 ast_el_initialize();
2417 el_set(el, EL_GETCFN, ast_el_read_char);
2419 if (!ast_strlen_zero(filename))
2420 ast_el_read_history(filename);
2422 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2425 fds.fd = ast_consock;
2426 fds.events = POLLIN;
2428 while (poll(&fds, 1, 100) > 0)
2429 ast_el_read_char(el, &tempchar);
2433 ebuf = (char *)el_gets(el, &num);
2435 if (!ebuf && write(1, "", 1) < 0)
2438 if (!ast_strlen_zero(ebuf)) {
2439 if (ebuf[strlen(ebuf)-1] == '\n')
2440 ebuf[strlen(ebuf)-1] = '\0';
2441 if (!remoteconsolehandler(ebuf)) {
2442 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2444 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2450 printf("\nDisconnected from Asterisk server\n");
2453 static int show_version(void)
2455 printf("Asterisk %s\n", ast_get_version());
2459 static int show_cli_help(void) {
2460 printf("Asterisk %s, Copyright (C) 1999 - 2008, Digium, Inc. and others.\n", ast_get_version());
2461 printf("Usage: asterisk [OPTIONS]\n");
2462 printf("Valid Options:\n");
2463 printf(" -V Display version number and exit\n");
2464 printf(" -C <configfile> Use an alternate configuration file\n");
2465 printf(" -G <group> Run as a group other than the caller\n");
2466 printf(" -U <user> Run as a user other than the caller\n");
2467 printf(" -c Provide console CLI\n");
2468 printf(" -d Enable extra debugging\n");
2469 #if HAVE_WORKING_FORK
2470 printf(" -f Do not fork\n");
2471 printf(" -F Always fork\n");
2473 printf(" -g Dump core in case of a crash\n");
2474 printf(" -h This help screen\n");
2475 printf(" -i Initialize crypto keys at startup\n");
2476 printf(" -I Enable internal timing if Zaptel timer is available\n");
2477 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2478 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2479 printf(" -m Mute debugging and console output on the console\n");
2480 printf(" -n Disable console colorization\n");
2481 printf(" -p Run as pseudo-realtime thread\n");
2482 printf(" -q Quiet mode (suppress output)\n");
2483 printf(" -r Connect to Asterisk on this machine\n");
2484 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2485 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2486 printf(" belong after they are done\n");
2487 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2488 printf(" of output to the CLI\n");
2489 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2490 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2491 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
2496 static void ast_readconfig(void)
2498 struct ast_config *cfg;
2499 struct ast_variable *v;
2500 char *config = DEFAULT_CONFIG_FILE;
2501 char hostname[MAXHOSTNAMELEN] = "";
2502 struct ast_flags config_flags = { 0 };
2504 unsigned int dbdir:1;
2505 unsigned int keydir:1;
2508 if (ast_opt_override_config) {
2509 cfg = ast_config_load(ast_config_AST_CONFIG_FILE, config_flags);
2511 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2513 cfg = ast_config_load(config, config_flags);
2515 /* init with buildtime config */
2516 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2517 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2518 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2519 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir) - 1, "%s/monitor", cfg_paths.spool_dir);
2520 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2521 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2522 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2523 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2524 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2525 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2526 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2527 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2528 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2530 /* no asterisk.conf? no problem, use buildtime config! */
2535 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2536 if (!strcasecmp(v->name, "astctlpermissions"))
2537 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2538 else if (!strcasecmp(v->name, "astctlowner"))
2539 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2540 else if (!strcasecmp(v->name, "astctlgroup"))
2541 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2542 else if (!strcasecmp(v->name, "astctl"))
2543 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2546 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2547 if (!strcasecmp(v->name, "astetcdir")) {
2548 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2549 } else if (!strcasecmp(v->name, "astspooldir")) {
2550 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2551 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir) - 1, "%s/monitor", v->value);
2552 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2553 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2555 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2556 } else if (!strcasecmp(v->name, "astdbdir")) {
2557 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2559 } else if (!strcasecmp(v->name, "astdatadir")) {
2560 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2562 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2563 } else if (!strcasecmp(v->name, "astkeydir")) {
2564 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2566 } else if (!strcasecmp(v->name, "astlogdir")) {
2567 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2568 } else if (!strcasecmp(v->name, "astagidir")) {
2569 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2570 } else if (!strcasecmp(v->name, "astrundir")) {
2571 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2572 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2573 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2574 } else if (!strcasecmp(v->name, "astmoddir")) {
2575 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2579 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2580 /* verbose level (-v at startup) */
2581 if (!strcasecmp(v->name, "verbose")) {
2582 option_verbose = atoi(v->value);
2583 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2584 } else if (!strcasecmp(v->name, "timestamp")) {
2585 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2586 /* whether or not to support #exec in config files */
2587 } else if (!strcasecmp(v->name, "execincludes")) {
2588 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2589 /* debug level (-d at startup) */
2590 } else if (!strcasecmp(v->name, "debug")) {
2592 if (sscanf(v->value, "%d", &option_debug) != 1) {
2593 option_debug = ast_true(v->value);
2595 #if HAVE_WORKING_FORK
2596 /* Disable forking (-f at startup) */
2597 } else if (!strcasecmp(v->name, "nofork")) {
2598 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2599 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2600 } else if (!strcasecmp(v->name, "alwaysfork")) {
2601 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2603 /* Run quietly (-q at startup ) */
2604 } else if (!strcasecmp(v->name, "quiet")) {
2605 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2606 /* Run as console (-c at startup, implies nofork) */
2607 } else if (!strcasecmp(v->name, "console")) {
2608 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2609 /* Run with high priority if the O/S permits (-p at startup) */
2610 } else if (!strcasecmp(v->name, "highpriority")) {
2611 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2612 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2613 } else if (!strcasecmp(v->name, "initcrypto")) {
2614 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2615 /* Disable ANSI colors for console (-c at startup) */
2616 } else if (!strcasecmp(v->name, "nocolor")) {
2617 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2618 /* Disable some usage warnings for picky people :p */
2619 } else if (!strcasecmp(v->name, "dontwarn")) {
2620 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2621 /* Dump core in case of crash (-g) */
2622 } else if (!strcasecmp(v->name, "dumpcore")) {
2623 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2624 /* Cache recorded sound files to another directory during recording */
2625 } else if (!strcasecmp(v->name, "cache_record_files")) {
2626 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2627 /* Specify cache directory */
2628 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2629 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2630 /* Build transcode paths via SLINEAR, instead of directly */
2631 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2632 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2633 /* Transmit SLINEAR silence while a channel is being recorded */
2634 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2635 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2636 /* Enable internal timing */
2637 } else if (!strcasecmp(v->name, "internal_timing")) {
2638 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2639 } else if (!strcasecmp(v->name, "maxcalls")) {
2640 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2641 option_maxcalls = 0;
2643 } else if (!strcasecmp(v->name, "maxload")) {
2646 if (getloadavg(test, 1) == -1) {
2647 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2648 option_maxload = 0.0;
2649 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2650 option_maxload = 0.0;
2652 /* Set the maximum amount of open files */
2653 } else if (!strcasecmp(v->name, "maxfiles")) {
2654 option_maxfiles = atoi(v->value);
2655 set_ulimit(option_maxfiles);
2656 /* What user to run as */
2657 } else if (!strcasecmp(v->name, "runuser")) {
2658 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
2659 /* What group to run as */
2660 } else if (!strcasecmp(v->name, "rungroup")) {
2661 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
2662 } else if (!strcasecmp(v->name, "systemname")) {
2663 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
2664 } else if (!strcasecmp(v->name, "autosystemname")) {
2665 if (ast_true(v->value)) {
2666 if (!gethostname(hostname, sizeof(hostname) - 1))
2667 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
2669 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2670 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
2672 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2675 } else if (!strcasecmp(v->name, "languageprefix")) {
2676 ast_language_is_prefix = ast_true(v->value);
2677 } else if (!strcasecmp(v->name, "lockmode")) {
2678 if (!strcasecmp(v->value, "lockfile")) {
2679 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2680 } else if (!strcasecmp(v->value, "flock")) {
2681 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
2683 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
2684 "defaulting to 'lockfile'\n", v->value);
2685 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2687 #if defined(HAVE_SYSINFO)
2688 } else if (!strcasecmp(v->name, "minmemfree")) {
2689 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
2690 * if the amount of free memory falls below this watermark */
2691 if ((sscanf(v->value, "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2692 option_minmemfree = 0;
2697 ast_config_destroy(cfg);
2700 static void *monitor_sig_flags(void *unused)
2703 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2706 if (sig_flags.need_reload) {
2707 sig_flags.need_reload = 0;
2708 ast_module_reload(NULL);
2710 if (sig_flags.need_quit) {
2711 sig_flags.need_quit = 0;
2712 quit_handler(0, 0, 1, 0);
2714 read(sig_alert_pipe[0], &a, sizeof(a));
2720 static void *canary_thread(void *unused)
2722 struct stat canary_stat;
2725 /* Give the canary time to sing */
2729 stat(canary_filename, &canary_stat);
2731 if (tv.tv_sec > canary_stat.st_mtime + 60) {
2732 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");
2733 ast_set_priority(0);
2737 /* Check the canary once a minute */
2742 /* Used by libc's atexit(3) function */
2743 static void canary_exit(void)
2746 kill(canary_pid, SIGKILL);
2749 static void run_startup_commands(void)
2752 struct ast_config *cfg;
2753 struct ast_flags cfg_flags = { 0 };
2754 struct ast_variable *v;
2756 if (!(cfg = ast_config_load("cli.conf", cfg_flags)))
2759 fd = open("/dev/null", O_RDWR);
2763 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
2764 if (ast_true(v->value))
2765 ast_cli_command(fd, v->name);
2769 ast_config_destroy(cfg);
2772 int main(int argc, char *argv[])
2775 char filename[80] = "";
2776 char hostname[MAXHOSTNAMELEN] = "";
2785 const char *runuser = NULL, *rungroup = NULL;
2786 char *remotesock = NULL;
2788 /* Remember original args for restart */
2789 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2790 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2791 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2793 for (x = 0; x < argc; x++)
2800 /* if the progname is rasterisk consider it a remote console */
2801 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2802 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2804 if (gethostname(hostname, sizeof(hostname)-1))
2805 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2806 ast_mainpid = getpid();
2810 ast_builtins_init();
2815 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2816 /* Check for options */
2817 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:s:")) != -1) {
2819 #if defined(HAVE_SYSINFO)
2821 if ((sscanf(&optarg[1], "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2822 option_minmemfree = 0;
2826 #if HAVE_WORKING_FORK
2828 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2831 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2836 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2839 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2842 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2845 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2848 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2851 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2855 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2858 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2861 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2862 option_maxcalls = 0;
2865 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2866 option_maxload = 0.0;
2869 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2872 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2875 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2878 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2879 xarg = ast_strdupa(optarg);
2882 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
2883 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2886 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2889 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2892 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2901 runuser = ast_strdupa(optarg);
2904 rungroup = ast_strdupa(optarg);
2907 remotesock = ast_strdupa(optarg);
2914 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2915 ast_register_verbose(console_verboser);
2919 if (ast_opt_console && !option_verbose)
2920 ast_verbose("[ Booting...\n");
2922 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2923 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2924 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2927 /* For remote connections, change the name of the remote connection.
2928 * We do this for the benefit of init scripts (which need to know if/when
2929 * the main asterisk process has died yet). */
2930 if (ast_opt_remote) {
2931 strcpy(argv[0], "rasterisk");
2932 for (x = 1; x < argc; x++) {
2933 argv[x] = argv[0] + 10;
2937 if (ast_opt_console && !option_verbose)
2938 ast_verbose("[ Reading Master Configuration ]\n");
2941 if (ast_opt_remote && remotesock != NULL)
2942 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
2944 if (!ast_language_is_prefix && !ast_opt_remote)
2945 ast_log(LOG_WARNING, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n");
2947 if (ast_opt_dump_core) {
2949 memset(&l, 0, sizeof(l));
2950 l.rlim_cur = RLIM_INFINITY;
2951 l.rlim_max = RLIM_INFINITY;
2952 if (setrlimit(RLIMIT_CORE, &l)) {
2953 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2957 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2958 rungroup = ast_config_AST_RUN_GROUP;
2959 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2960 runuser = ast_config_AST_RUN_USER;
2962 /* Must install this signal handler up here to ensure that if the canary
2963 * fails to execute that it doesn't kill the Asterisk process.
2965 signal(SIGCHLD, child_handler);
2970 ast_set_priority(ast_opt_high_priority);
2971 if (ast_opt_high_priority) {
2972 snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
2974 canary_pid = fork();
2975 if (canary_pid == 0) {
2976 char canary_binary[128], *lastslash;
2979 /* Reset signal handler */
2980 signal(SIGCHLD, SIG_DFL);
2982 for (fd = 0; fd < 100; fd++)
2985 execlp("astcanary", "astcanary", canary_filename, (char *)NULL);
2987 /* If not found, try the same path as used to execute asterisk */
2988 ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
2989 if ((lastslash = strrchr(canary_binary, '/'))) {
2990 ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
2991 execl(canary_binary, "astcanary", canary_filename, (char *)NULL);
2994 /* Should never happen */
2996 } else if (canary_pid > 0) {
2997 pthread_t dont_care;
2998 ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
3001 /* Kill the canary when we exit */
3002 atexit(canary_exit);
3006 if (isroot && rungroup) {
3008 gr = getgrnam(rungroup);
3010 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
3013 if (setgid(gr->gr_gid)) {
3014 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
3017 if (setgroups(0, NULL)) {
3018 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
3022 ast_verbose("Running as group '%s'\n", rungroup);
3025 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
3028 #endif /* HAVE_CAP */
3030 pw = getpwnam(runuser);
3032 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
3036 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
3037 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
3040 #endif /* HAVE_CAP */
3041 if (!isroot && pw->pw_uid != geteuid()) {
3042 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
3046 if (setgid(pw->pw_gid)) {
3047 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
3050 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
3051 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
3055 if (setuid(pw->pw_uid)) {
3056 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
3060 ast_verbose("Running as user '%s'\n", runuser);
3065 cap = cap_from_text("cap_net_admin=ep");
3067 if (cap_set_proc(cap))
3068 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
3071 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
3073 #endif /* HAVE_CAP */
3076 #endif /* __CYGWIN__ */
3079 if (geteuid() && ast_opt_dump_core) {
3080 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
3081 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
3090 if (ast_opt_console && !option_verbose)
3091 ast_verbose("[ Initializing Custom Configuration Options ]\n");
3092 /* custom config setup */
3093 register_config_cli();
3096 if (ast_opt_console) {
3097 if (el_hist == NULL || el == NULL)
3098 ast_el_initialize();
3100 if (!ast_strlen_zero(filename))
3101 ast_el_read_history(filename);
3104 if (ast_tryconnect()) {
3105 /* One is already running */
3106 if (ast_opt_remote) {
3108 ast_remotecontrol(xarg);
3109 quit_handler(0, 0, 0, 0);
3112 printf(term_quit());
3113 ast_remotecontrol(NULL);
3114 quit_handler(0, 0, 0, 0);
3117 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
3118 printf(term_quit());
3121 } else if (ast_opt_remote || ast_opt_exec) {
3122 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
3123 printf(term_quit());
3126 /* Blindly write pid file since we couldn't connect */
3127 unlink(ast_config_AST_PID);
3128 f = fopen(ast_config_AST_PID, "w");
3130 fprintf(f, "%ld\n", (long)getpid());
3133 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
3135 #if HAVE_WORKING_FORK
3136 if (ast_opt_always_fork || !ast_opt_no_fork) {
3137 #ifndef HAVE_SBIN_LAUNCHD
3139 ast_mainpid = getpid();
3140 /* Blindly re-write pid file since we are forking */
3141 unlink(ast_config_AST_PID);
3142 f = fopen(ast_config_AST_PID, "w");
3144 fprintf(f, "%ld\n", (long)ast_mainpid);
3147 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
3149 ast_log(LOG_WARNING, "Mac OS X detected. Use '/sbin/launchd -d' to launch with the nofork option.\n");
3154 /* Test recursive mutex locking. */
3155 if (test_for_thread_safety())
3156 ast_verbose("Warning! Asterisk is not thread safe.\n");
3162 sigaddset(&sigs, SIGHUP);
3163 sigaddset(&sigs, SIGTERM);
3164 sigaddset(&sigs, SIGINT);
3165 sigaddset(&sigs, SIGPIPE);
3166 sigaddset(&sigs, SIGWINCH);
3167 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
3168 signal(SIGURG, urg_handler);
3169 signal(SIGINT, __quit_handler);
3170 signal(SIGTERM, __quit_handler);
3171 signal(SIGHUP, hup_handler);
3172 signal(SIGPIPE, SIG_IGN);
3174 /* ensure that the random number generators are seeded with a different value every time
3177 srand((unsigned int) getpid() + (unsigned int) time(NULL));
3178 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
3180 if (init_logger()) { /* Start logging subsystem */
3181 printf(term_quit());
3185 threadstorage_init();
3189 if (load_modules(1)) { /* Load modules, pre-load only */
3190 printf(term_quit());
3194 if (dnsmgr_init()) { /* Initialize the DNS manager */
3195 printf(term_quit());
3199 ast_http_init(); /* Start the HTTP server, if needed */
3201 ast_channels_init();
3203 if (init_manager()) {
3204 printf(term_quit());
3208 if (ast_cdr_engine_init()) {
3209 printf(term_quit());
3213 if (ast_device_state_engine_init()) {
3214 printf(term_quit());
3222 if (ast_image_init()) {
3223 printf(term_quit());
3227 if (ast_file_init()) {
3228 printf(term_quit());
3233 printf(term_quit());
3237 ast_features_init();
3239 if (init_framer()) {
3240 printf(term_quit());
3245 printf(term_quit());
3249 if (ast_enum_init()) {
3250 printf(term_quit());
3254 if (load_modules(0)) {
3255 printf(term_quit());
3259 dnsmgr_start_refresh();
3261 /* We might have the option of showing a console, but for now just
3263 if (ast_opt_console && !option_verbose)
3264 ast_verbose(" ]\n");
3265 if (option_verbose || ast_opt_console)
3266 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
3267 if (ast_opt_no_fork)
3268 consolethread = pthread_self();
3270 if (pipe(sig_alert_pipe))
3271 sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
3273 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
3274 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
3276 #ifdef __AST_DEBUG_MALLOC
3280 ast_lastreloadtime = ast_startuptime = ast_tvnow();
3281 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
3283 run_startup_commands();
3285 if (ast_opt_console) {
3286 /* Console stuff now... */
3287 /* Register our quit function */
3289 pthread_t dont_care;
3291 ast_pthread_create_detached(&dont_care, NULL, monitor_sig_flags, NULL);
3293 set_icon("Asterisk");
3294 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
3298 buf = (char *) el_gets(el, &num);
3300 if (!buf && write(1, "", 1) < 0)
3304 if (buf[strlen(buf)-1] == '\n')
3305 buf[strlen(buf)-1] = '\0';
3307 consolehandler((char *)buf);
3308 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
3309 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
3310 /* Whoa, stdout disappeared from under us... Make /dev/null's */
3312 fd = open("/dev/null", O_RDWR);
3314 dup2(fd, STDOUT_FILENO);
3315 dup2(fd, STDIN_FILENO);
3317 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
3323 monitor_sig_flags(NULL);