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/ast_version.h"
121 #include "asterisk/linkedlists.h"
122 #include "asterisk/devicestate.h"
123 #include "asterisk/module.h"
124 #include "asterisk/dsp.h"
125 #include "asterisk/zapata.h"
127 #include "asterisk/doxyref.h" /* Doxygen documentation */
129 #include "../defaults.h"
132 #define AF_LOCAL AF_UNIX
133 #define PF_LOCAL PF_UNIX
136 #define AST_MAX_CONNECTS 128
139 /*! \brief Welcome message when starting a CLI interface */
140 #define WELCOME_MESSAGE \
141 ast_verbose("Asterisk %s, Copyright (C) 1999 - 2008 Digium, Inc. and others.\n" \
142 "Created by Mark Spencer <markster@digium.com>\n" \
143 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
144 "This is free software, with components licensed under the GNU General Public\n" \
145 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
146 "certain conditions. Type 'core show license' for details.\n" \
147 "=========================================================================\n", ast_get_version()) \
149 /*! \defgroup main_options Main Configuration Options
150 * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
151 * \arg \ref Config_ast "asterisk.conf"
152 * \note Some of them can be changed in the CLI
156 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
158 int option_verbose; /*!< Verbosity level */
159 int option_debug; /*!< Debug level */
160 double option_maxload; /*!< Max load avg on system */
161 int option_maxcalls; /*!< Max number of active calls */
162 int option_maxfiles; /*!< Max number of open file handles (files, sockets) */
163 #if defined(HAVE_SYSINFO)
164 long option_minmemfree; /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
169 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
170 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
172 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
173 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
176 int fd; /*!< File descriptor */
177 int p[2]; /*!< Pipe */
178 pthread_t t; /*!< Thread of handler */
179 int mute; /*!< Is the console muted for logs */
184 AST_RWLIST_ENTRY(ast_atexit) list;
187 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
189 struct timeval ast_startuptime;
190 struct timeval ast_lastreloadtime;
192 static History *el_hist;
194 static char *remotehostname;
196 struct console consoles[AST_MAX_CONNECTS];
198 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
200 static int ast_el_add_history(char *);
201 static int ast_el_read_history(char *);
202 static int ast_el_write_history(char *);
205 char config_dir[PATH_MAX];
206 char module_dir[PATH_MAX];
207 char spool_dir[PATH_MAX];
208 char monitor_dir[PATH_MAX];
209 char var_dir[PATH_MAX];
210 char data_dir[PATH_MAX];
211 char log_dir[PATH_MAX];
212 char agi_dir[PATH_MAX];
213 char run_dir[PATH_MAX];
214 char key_dir[PATH_MAX];
216 char config_file[PATH_MAX];
217 char db_path[PATH_MAX];
218 char pid_path[PATH_MAX];
219 char socket_path[PATH_MAX];
220 char run_user[PATH_MAX];
221 char run_group[PATH_MAX];
222 char system_name[128];
225 static struct _cfg_paths cfg_paths;
227 const char *ast_config_AST_CONFIG_DIR = cfg_paths.config_dir;
228 const char *ast_config_AST_CONFIG_FILE = cfg_paths.config_file;
229 const char *ast_config_AST_MODULE_DIR = cfg_paths.module_dir;
230 const char *ast_config_AST_SPOOL_DIR = cfg_paths.spool_dir;
231 const char *ast_config_AST_MONITOR_DIR = cfg_paths.monitor_dir;
232 const char *ast_config_AST_VAR_DIR = cfg_paths.var_dir;
233 const char *ast_config_AST_DATA_DIR = cfg_paths.data_dir;
234 const char *ast_config_AST_LOG_DIR = cfg_paths.log_dir;
235 const char *ast_config_AST_AGI_DIR = cfg_paths.agi_dir;
236 const char *ast_config_AST_KEY_DIR = cfg_paths.key_dir;
237 const char *ast_config_AST_RUN_DIR = cfg_paths.run_dir;
239 const char *ast_config_AST_DB = cfg_paths.db_path;
240 const char *ast_config_AST_PID = cfg_paths.pid_path;
241 const char *ast_config_AST_SOCKET = cfg_paths.socket_path;
242 const char *ast_config_AST_RUN_USER = cfg_paths.run_user;
243 const char *ast_config_AST_RUN_GROUP = cfg_paths.run_group;
244 const char *ast_config_AST_SYSTEM_NAME = cfg_paths.system_name;
246 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
247 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
248 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
249 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
251 extern const char *ast_build_hostname;
252 extern const char *ast_build_kernel;
253 extern const char *ast_build_machine;
254 extern const char *ast_build_os;
255 extern const char *ast_build_date;
256 extern const char *ast_build_user;
258 static char *_argv[256];
259 static int shuttingdown;
260 static int restartnow;
261 static pthread_t consolethread = AST_PTHREADT_NULL;
262 static int canary_pid = 0;
263 static char canary_filename[128];
265 static char randompool[256];
267 static int sig_alert_pipe[2] = { -1, -1 };
269 unsigned int need_reload:1;
270 unsigned int need_quit:1;
273 #if !defined(LOW_MEMORY)
274 struct file_version {
275 AST_RWLIST_ENTRY(file_version) list;
280 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
282 void ast_register_file_version(const char *file, const char *version)
284 struct file_version *new;
286 size_t version_length;
288 work = ast_strdupa(version);
289 work = ast_strip(ast_strip_quoted(work, "$", "$"));
290 version_length = strlen(work) + 1;
292 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
296 new->version = (char *) new + sizeof(*new);
297 memcpy(new->version, work, version_length);
298 AST_RWLIST_WRLOCK(&file_versions);
299 AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
300 AST_RWLIST_UNLOCK(&file_versions);
303 void ast_unregister_file_version(const char *file)
305 struct file_version *find;
307 AST_RWLIST_WRLOCK(&file_versions);
308 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
309 if (!strcasecmp(find->file, file)) {
310 AST_RWLIST_REMOVE_CURRENT(list);
314 AST_RWLIST_TRAVERSE_SAFE_END;
315 AST_RWLIST_UNLOCK(&file_versions);
321 /*! \brief Find version for given module name */
322 const char *ast_file_version_find(const char *file)
324 struct file_version *iterator;
326 AST_RWLIST_WRLOCK(&file_versions);
327 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, iterator, list) {
328 if (!strcasecmp(iterator->file, file))
331 AST_RWLIST_TRAVERSE_SAFE_END;
332 AST_RWLIST_UNLOCK(&file_versions);
334 return iterator->version;
340 struct thread_list_t {
341 AST_RWLIST_ENTRY(thread_list_t) list;
346 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
348 void ast_register_thread(char *name)
350 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
354 new->id = pthread_self();
355 new->name = name; /* steal the allocated memory for the thread name */
356 AST_RWLIST_WRLOCK(&thread_list);
357 AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
358 AST_RWLIST_UNLOCK(&thread_list);
361 void ast_unregister_thread(void *id)
363 struct thread_list_t *x;
365 AST_RWLIST_WRLOCK(&thread_list);
366 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
367 if ((void *) x->id == id) {
368 AST_RWLIST_REMOVE_CURRENT(list);
372 AST_RWLIST_TRAVERSE_SAFE_END;
373 AST_RWLIST_UNLOCK(&thread_list);
380 /*! \brief Give an overview of core settings */
381 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
388 e->command = "core show settings";
389 e->usage = "Usage: core show settings\n"
390 " Show core misc settings";
396 ast_cli(a->fd, "\nPBX Core settings\n");
397 ast_cli(a->fd, "-----------------\n");
398 ast_cli(a->fd, " Version: %s\n", ast_get_version());
400 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
402 ast_cli(a->fd, " Maximum calls: Not set\n");
404 ast_cli(a->fd, " Maximum open file handles: %d\n", option_maxfiles);
406 ast_cli(a->fd, " Maximum open file handles: Not set\n");
407 ast_cli(a->fd, " Verbosity: %d\n", option_verbose);
408 ast_cli(a->fd, " Debug level: %d\n", option_debug);
409 ast_cli(a->fd, " Maximum load average: %lf\n", option_maxload);
410 #if defined(HAVE_SYSINFO)
411 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
413 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
414 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
415 ast_cli(a->fd, " Startup time: %s\n", buf);
417 if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
418 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
419 ast_cli(a->fd, " Last reload time: %s\n", buf);
421 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);
422 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
423 ast_cli(a->fd, " Default language: %s\n", defaultlanguage);
424 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
425 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
426 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
427 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
428 ast_cli(a->fd, " Internal timing: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
429 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
431 ast_cli(a->fd, "\n* Subsystems\n");
432 ast_cli(a->fd, " -------------\n");
433 ast_cli(a->fd, " Manager (AMI): %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
434 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
435 ast_cli(a->fd, " Call data records: %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
436 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
438 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
440 ast_cli(a->fd, "\n* Directories\n");
441 ast_cli(a->fd, " -------------\n");
442 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
443 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
444 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
445 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
446 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
447 ast_cli(a->fd, "\n\n");
451 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
454 struct thread_list_t *cur;
457 e->command = "core show threads";
459 "Usage: core show threads\n"
460 " List threads currently active in the system.\n";
466 AST_RWLIST_RDLOCK(&thread_list);
467 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
468 ast_cli(a->fd, "%p %s\n", (void *)cur->id, cur->name);
471 AST_RWLIST_UNLOCK(&thread_list);
472 ast_cli(a->fd, "%d threads listed.\n", count);
476 #if defined(HAVE_SYSINFO)
477 /*! \brief Give an overview of system statistics */
478 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
480 struct sysinfo sys_info;
483 e->command = "core show sysinfo";
485 "Usage: core show sysinfo\n"
486 " List current system information.\n";
491 if (sysinfo(&sys_info)) {
492 ast_cli(a->fd, "FAILED to retrieve system information\n\n");
495 ast_cli(a->fd, "\nSystem Statistics\n");
496 ast_cli(a->fd, "-----------------\n");
497 ast_cli(a->fd, " System Uptime: %ld hours\n", sys_info.uptime/3600);
498 ast_cli(a->fd, " Total RAM: %ld KiB\n", (sys_info.totalram / sys_info.mem_unit)/1024);
499 ast_cli(a->fd, " Free RAM: %ld KiB\n", (sys_info.freeram / sys_info.mem_unit)/1024);
500 ast_cli(a->fd, " Buffer RAM: %ld KiB\n", (sys_info.bufferram / sys_info.mem_unit)/1024);
501 ast_cli(a->fd, " Total Swap Space: %ld KiB\n", (sys_info.totalswap / sys_info.mem_unit)/1024);
502 ast_cli(a->fd, " Free Swap Space: %ld KiB\n\n", (sys_info.freeswap / sys_info.mem_unit)/1024);
503 ast_cli(a->fd, " Number of Processes: %d \n\n", sys_info.procs);
508 struct profile_entry {
510 uint64_t scale; /* if non-zero, values are scaled by this */
516 struct profile_data {
519 struct profile_entry e[0];
522 static struct profile_data *prof_data;
524 /*! \brief allocates a counter with a given name and scale.
525 * \return Returns the identifier of the counter.
527 int ast_add_profile(const char *name, uint64_t scale)
529 int l = sizeof(struct profile_data);
530 int n = 10; /* default entries */
532 if (prof_data == NULL) {
533 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
534 if (prof_data == NULL)
536 prof_data->entries = 0;
537 prof_data->max_size = n;
539 if (prof_data->entries >= prof_data->max_size) {
541 n = prof_data->max_size + 20;
542 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
546 prof_data->max_size = n;
548 n = prof_data->entries++;
549 prof_data->e[n].name = ast_strdup(name);
550 prof_data->e[n].value = 0;
551 prof_data->e[n].events = 0;
552 prof_data->e[n].mark = 0;
553 prof_data->e[n].scale = scale;
557 int64_t ast_profile(int i, int64_t delta)
559 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
561 if (prof_data->e[i].scale > 1)
562 delta /= prof_data->e[i].scale;
563 prof_data->e[i].value += delta;
564 prof_data->e[i].events++;
565 return prof_data->e[i].value;
568 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
569 #if defined(__FreeBSD__)
570 #include <machine/cpufunc.h>
572 static __inline uint64_t
577 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
581 #else /* supply a dummy function on other platforms */
582 static __inline uint64_t
589 int64_t ast_mark(int i, int startstop)
591 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
594 prof_data->e[i].mark = rdtsc();
596 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
597 if (prof_data->e[i].scale > 1)
598 prof_data->e[i].mark /= prof_data->e[i].scale;
599 prof_data->e[i].value += prof_data->e[i].mark;
600 prof_data->e[i].events++;
602 return prof_data->e[i].mark;
605 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
606 max = prof_data->entries;\
607 if (a->argc > 3) { /* specific entries */ \
608 if (isdigit(a->argv[3][0])) { \
609 min = atoi(a->argv[3]); \
610 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
611 max = atoi(a->argv[4]); \
613 search = a->argv[3]; \
615 if (max > prof_data->entries) \
616 max = prof_data->entries;
618 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
624 e->command = "core show profile";
625 e->usage = "Usage: core show profile\n"
626 " show profile information";
632 if (prof_data == NULL)
635 DEFINE_PROFILE_MIN_MAX_VALUES;
636 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
637 prof_data->entries, prof_data->max_size);
638 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
639 "Value", "Average", "Name");
640 for (i = min; i < max; i++) {
641 struct profile_entry *e = &prof_data->e[i];
642 if (!search || strstr(prof_data->e[i].name, search))
643 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
646 (long)e->events, (long long)e->value,
647 (long long)(e->events ? e->value / e->events : e->value),
653 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
659 e->command = "core clear profile";
660 e->usage = "Usage: core clear profile\n"
661 " clear profile information";
667 if (prof_data == NULL)
670 DEFINE_PROFILE_MIN_MAX_VALUES;
671 for (i= min; i < max; i++) {
672 if (!search || strstr(prof_data->e[i].name, search)) {
673 prof_data->e[i].value = 0;
674 prof_data->e[i].events = 0;
679 #undef DEFINE_PROFILE_MIN_MAX_VALUES
681 /*! \brief CLI command to list module versions */
682 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
684 #define FORMAT "%-25.25s %-40.40s\n"
685 struct file_version *iterator;
691 int matchlen, which = 0;
692 struct file_version *find;
696 e->command = "core show file version [like]";
698 "Usage: core show file version [like <pattern>]\n"
699 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
700 " Optional regular expression pattern is used to filter the file list.\n";
703 matchlen = strlen(a->word);
706 AST_RWLIST_RDLOCK(&file_versions);
707 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
708 if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
709 ret = ast_strdup(find->file);
713 AST_RWLIST_UNLOCK(&file_versions);
720 if (!strcasecmp(a->argv[4], "like")) {
721 if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
722 return CLI_SHOWUSAGE;
725 return CLI_SHOWUSAGE;
733 return CLI_SHOWUSAGE;
736 ast_cli(a->fd, FORMAT, "File", "Revision");
737 ast_cli(a->fd, FORMAT, "----", "--------");
738 AST_RWLIST_RDLOCK(&file_versions);
739 AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
740 if (havename && strcasecmp(iterator->file, a->argv[4]))
743 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
746 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
751 AST_RWLIST_UNLOCK(&file_versions);
753 ast_cli(a->fd, "%d files listed.\n", count_files);
763 #endif /* ! LOW_MEMORY */
765 int ast_register_atexit(void (*func)(void))
767 struct ast_atexit *ae;
769 if (!(ae = ast_calloc(1, sizeof(*ae))))
774 ast_unregister_atexit(func);
776 AST_RWLIST_WRLOCK(&atexits);
777 AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
778 AST_RWLIST_UNLOCK(&atexits);
783 void ast_unregister_atexit(void (*func)(void))
785 struct ast_atexit *ae = NULL;
787 AST_RWLIST_WRLOCK(&atexits);
788 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
789 if (ae->func == func) {
790 AST_RWLIST_REMOVE_CURRENT(list);
794 AST_RWLIST_TRAVERSE_SAFE_END;
795 AST_RWLIST_UNLOCK(&atexits);
801 static int fdprint(int fd, const char *s)
803 return write(fd, s, strlen(s) + 1);
806 /*! \brief NULL handler so we can collect the child exit status */
807 static void null_sig_handler(int signal)
812 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
813 /*! \brief Keep track of how many threads are currently trying to wait*() on
815 static unsigned int safe_system_level = 0;
816 static void *safe_system_prev_handler;
818 void ast_replace_sigchld(void)
822 ast_mutex_lock(&safe_system_lock);
823 level = safe_system_level++;
825 /* only replace the handler if it has not already been done */
827 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
829 ast_mutex_unlock(&safe_system_lock);
832 void ast_unreplace_sigchld(void)
836 ast_mutex_lock(&safe_system_lock);
837 level = --safe_system_level;
839 /* only restore the handler if we are the last one */
841 signal(SIGCHLD, safe_system_prev_handler);
843 ast_mutex_unlock(&safe_system_lock);
846 int ast_safe_system(const char *s)
849 #ifdef HAVE_WORKING_FORK
853 struct rusage rusage;
856 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
857 ast_replace_sigchld();
859 #ifdef HAVE_WORKING_FORK
866 #ifdef HAVE_WORKING_FORK
867 if (ast_opt_high_priority)
869 /* Close file descriptors and launch system command */
870 for (x = STDERR_FILENO + 1; x < 4096; x++)
873 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
875 } else if (pid > 0) {
877 res = wait4(pid, &status, 0, &rusage);
879 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
881 } else if (errno != EINTR)
885 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
889 ast_unreplace_sigchld();
898 * \brief mute or unmute a console from logging
900 void ast_console_toggle_mute(int fd, int silent) {
902 for (x = 0;x < AST_MAX_CONNECTS; x++) {
903 if (fd == consoles[x].fd) {
904 if (consoles[x].mute) {
905 consoles[x].mute = 0;
907 ast_cli(fd, "Console is not muted anymore.\n");
909 consoles[x].mute = 1;
911 ast_cli(fd, "Console is muted.\n");
916 ast_cli(fd, "Couldn't find remote console.\n");
920 * \brief log the string to all attached console clients
922 static void ast_network_puts_mutable(const char *string)
925 for (x = 0;x < AST_MAX_CONNECTS; x++) {
926 if (consoles[x].mute)
928 if (consoles[x].fd > -1)
929 fdprint(consoles[x].p[1], string);
934 * \brief log the string to the console, and all attached
937 void ast_console_puts_mutable(const char *string)
939 fputs(string, stdout);
941 ast_network_puts_mutable(string);
945 * \brief write the string to all attached console clients
947 static void ast_network_puts(const char *string)
950 for (x = 0; x < AST_MAX_CONNECTS; x++) {
951 if (consoles[x].fd > -1)
952 fdprint(consoles[x].p[1], string);
957 * write the string to the console, and all attached
960 void ast_console_puts(const char *string)
962 fputs(string, stdout);
964 ast_network_puts(string);
967 static void network_verboser(const char *s)
969 ast_network_puts_mutable(s);
972 static pthread_t lthread;
974 static void *netconsole(void *vconsole)
976 struct console *con = vconsole;
977 char hostname[MAXHOSTNAMELEN] = "";
980 struct pollfd fds[2];
982 if (gethostname(hostname, sizeof(hostname)-1))
983 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
984 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
985 fdprint(con->fd, tmp);
988 fds[0].events = POLLIN;
990 fds[1].fd = con->p[0];
991 fds[1].events = POLLIN;
994 res = poll(fds, 2, -1);
997 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1000 if (fds[0].revents) {
1001 res = read(con->fd, tmp, sizeof(tmp));
1006 ast_cli_command_multiple(con->fd, res, tmp);
1008 if (fds[1].revents) {
1009 res = read(con->p[0], tmp, sizeof(tmp));
1011 ast_log(LOG_ERROR, "read returned %d\n", res);
1014 res = write(con->fd, tmp, res);
1019 ast_verb(3, "Remote UNIX connection disconnected\n");
1028 static void *listener(void *unused)
1030 struct sockaddr_un sunaddr;
1035 struct pollfd fds[1];
1039 fds[0].fd = ast_socket;
1040 fds[0].events = POLLIN;
1041 s = poll(fds, 1, -1);
1042 pthread_testcancel();
1045 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1048 len = sizeof(sunaddr);
1049 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1052 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1054 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1055 if (consoles[x].fd < 0) {
1056 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1057 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1058 consoles[x].fd = -1;
1059 fdprint(s, "Server failed to create pipe\n");
1063 flags = fcntl(consoles[x].p[1], F_GETFL);
1064 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1066 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1067 if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1068 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1069 close(consoles[x].p[0]);
1070 close(consoles[x].p[1]);
1071 consoles[x].fd = -1;
1072 fdprint(s, "Server failed to spawn thread\n");
1078 if (x >= AST_MAX_CONNECTS) {
1079 fdprint(s, "No more connections allowed\n");
1080 ast_log(LOG_WARNING, "No more connections allowed\n");
1082 } else if (consoles[x].fd > -1)
1083 ast_verb(3, "Remote UNIX connection\n");
1089 static int ast_makesocket(void)
1091 struct sockaddr_un sunaddr;
1097 for (x = 0; x < AST_MAX_CONNECTS; x++)
1098 consoles[x].fd = -1;
1099 unlink(ast_config_AST_SOCKET);
1100 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1101 if (ast_socket < 0) {
1102 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1105 memset(&sunaddr, 0, sizeof(sunaddr));
1106 sunaddr.sun_family = AF_LOCAL;
1107 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1108 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1110 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1115 res = listen(ast_socket, 2);
1117 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1122 ast_register_verbose(network_verboser);
1123 ast_pthread_create_background(<hread, NULL, listener, NULL);
1125 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1127 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1128 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1133 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1135 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1136 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1141 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1142 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1144 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1147 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
1149 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1150 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1156 static int ast_tryconnect(void)
1158 struct sockaddr_un sunaddr;
1160 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1161 if (ast_consock < 0) {
1162 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1165 memset(&sunaddr, 0, sizeof(sunaddr));
1166 sunaddr.sun_family = AF_LOCAL;
1167 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1168 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1177 /*! \brief Urgent handler
1179 Called by soft_hangup to interrupt the poll, read, or other
1180 system call. We don't actually need to do anything though.
1181 Remember: Cannot EVER ast_log from within a signal handler
1183 static void urg_handler(int num)
1185 signal(num, urg_handler);
1189 static void hup_handler(int num)
1192 if (option_verbose > 1)
1193 printf("Received HUP signal -- Reloading configs\n");
1195 execvp(_argv[0], _argv);
1196 sig_flags.need_reload = 1;
1197 if (sig_alert_pipe[1] != -1)
1198 write(sig_alert_pipe[1], &a, sizeof(a));
1199 signal(num, hup_handler);
1202 static void child_handler(int sig)
1204 /* Must not ever ast_log or ast_verbose within signal handler */
1208 * Reap all dead children -- not just one
1210 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1212 if (n == 0 && option_debug)
1213 printf("Huh? Child handler, but nobody there?\n");
1214 signal(sig, child_handler);
1217 /*! \brief Set maximum open files */
1218 static void set_ulimit(int value)
1220 struct rlimit l = {0, 0};
1223 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1230 if (setrlimit(RLIMIT_NOFILE, &l)) {
1231 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1235 ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1240 /*! \brief Set an X-term or screen title */
1241 static void set_title(char *text)
1243 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1244 fprintf(stdout, "\033]2;%s\007", text);
1247 static void set_icon(char *text)
1249 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1250 fprintf(stdout, "\033]1;%s\007", text);
1253 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1254 else. If your PBX has heavy activity on it, this is a good thing. */
1255 int ast_set_priority(int pri)
1257 struct sched_param sched;
1258 memset(&sched, 0, sizeof(sched));
1261 sched.sched_priority = 10;
1262 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1263 ast_log(LOG_WARNING, "Unable to set high priority\n");
1267 ast_verbose("Set to realtime thread\n");
1269 sched.sched_priority = 0;
1270 /* According to the manpage, these parameters can never fail. */
1271 sched_setscheduler(0, SCHED_OTHER, &sched);
1275 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1276 ast_log(LOG_WARNING, "Unable to set high priority\n");
1280 ast_verbose("Set to high priority\n");
1282 /* According to the manpage, these parameters can never fail. */
1283 setpriority(PRIO_PROCESS, 0, 0);
1289 static void ast_run_atexits(void)
1291 struct ast_atexit *ae;
1292 AST_RWLIST_RDLOCK(&atexits);
1293 AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1297 AST_RWLIST_UNLOCK(&atexits);
1300 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1302 char filename[80] = "";
1305 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1306 ast_cdr_engine_term();
1310 /* Begin shutdown routine, hanging up active channels */
1311 ast_begin_shutdown(1);
1312 if (option_verbose && ast_opt_console)
1313 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1317 /* Wait up to 15 seconds for all channels to go away */
1320 if (!ast_active_channels())
1324 /* Sleep 1/10 of a second */
1329 ast_begin_shutdown(0);
1330 if (option_verbose && ast_opt_console)
1331 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1333 if (!ast_active_channels())
1341 if (!shuttingdown) {
1342 if (option_verbose && ast_opt_console)
1343 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1348 ast_module_shutdown();
1350 if (ast_opt_console || ast_opt_remote) {
1352 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1353 if (!ast_strlen_zero(filename))
1354 ast_el_write_history(filename);
1357 if (el_hist != NULL)
1358 history_end(el_hist);
1361 ast_verbose("Executing last minute cleanups\n");
1363 /* Called on exit */
1364 if (option_verbose && ast_opt_console)
1365 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1366 ast_debug(1, "Asterisk ending (%d).\n", num);
1367 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1368 if (ast_socket > -1) {
1369 pthread_cancel(lthread);
1372 unlink(ast_config_AST_SOCKET);
1374 if (ast_consock > -1)
1376 if (!ast_opt_remote)
1377 unlink(ast_config_AST_PID);
1378 printf("%s", term_quit());
1380 if (option_verbose || ast_opt_console)
1381 ast_verbose("Preparing for Asterisk restart...\n");
1382 /* Mark all FD's for closing on exec */
1383 for (x=3; x < 32768; x++) {
1384 fcntl(x, F_SETFD, FD_CLOEXEC);
1386 if (option_verbose || ast_opt_console)
1387 ast_verbose("Asterisk is now restarting...\n");
1393 /* If there is a consolethread running send it a SIGHUP
1394 so it can execvp, otherwise we can do it ourselves */
1395 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1396 pthread_kill(consolethread, SIGHUP);
1397 /* Give the signal handler some time to complete */
1400 execvp(_argv[0], _argv);
1409 static void __quit_handler(int num)
1412 sig_flags.need_quit = 1;
1413 if (sig_alert_pipe[1] != -1)
1414 write(sig_alert_pipe[1], &a, sizeof(a));
1415 /* There is no need to restore the signal handler here, since the app
1416 * is going to exit */
1419 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1422 if (!strncmp(s, cmp, strlen(cmp))) {
1423 c = s + strlen(cmp);
1424 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1430 static void console_verboser(const char *s)
1433 const char *c = NULL;
1435 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1436 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1437 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1438 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1446 /* Wake up a poll()ing console */
1447 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1448 pthread_kill(consolethread, SIGURG);
1451 static int ast_all_zeros(char *s)
1461 static void consolehandler(char *s)
1463 printf("%s", term_end());
1466 /* Called when readline data is available */
1467 if (!ast_all_zeros(s))
1468 ast_el_add_history(s);
1469 /* The real handler for bang */
1472 ast_safe_system(s+1);
1474 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1476 ast_cli_command(STDOUT_FILENO, s);
1479 static int remoteconsolehandler(char *s)
1483 /* Called when readline data is available */
1484 if (!ast_all_zeros(s))
1485 ast_el_add_history(s);
1486 /* The real handler for bang */
1489 ast_safe_system(s+1);
1491 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1494 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1495 (s[4] == '\0' || isspace(s[4]))) {
1496 quit_handler(0, 0, 0, 0);
1503 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1507 e->command = "core show version";
1509 "Usage: core show version\n"
1510 " Shows Asterisk version information.\n";
1517 return CLI_SHOWUSAGE;
1518 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1519 ast_get_version(), ast_build_user, ast_build_hostname,
1520 ast_build_machine, ast_build_os, ast_build_date);
1525 static int handle_quit(int fd, int argc, char *argv[])
1528 return RESULT_SHOWUSAGE;
1529 quit_handler(0, 0, 1, 0);
1530 return RESULT_SUCCESS;
1534 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1538 e->command = "core stop now";
1540 "Usage: core stop now\n"
1541 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1547 if (a->argc != e->args)
1548 return CLI_SHOWUSAGE;
1549 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1553 static char *handle_stop_now_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1555 char *res = handle_stop_now(e, cmd, a);
1556 if (cmd == CLI_INIT)
1557 e->command = "stop now";
1561 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1565 e->command = "core stop gracefully";
1567 "Usage: core stop gracefully\n"
1568 " Causes Asterisk to not accept new calls, and exit when all\n"
1569 " active calls have terminated normally.\n";
1575 if (a->argc != e->args)
1576 return CLI_SHOWUSAGE;
1577 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1581 static char *handle_stop_gracefully_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1583 char *res = handle_stop_gracefully(e, cmd, a);
1584 if (cmd == CLI_INIT)
1585 e->command = "stop gracefully";
1589 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1593 e->command = "core stop when convenient";
1595 "Usage: core stop when convenient\n"
1596 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1602 if (a->argc != e->args)
1603 return CLI_SHOWUSAGE;
1604 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
1605 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1609 static char *handle_stop_when_convenient_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1611 char *res = handle_stop_when_convenient(e, cmd, a);
1612 if (cmd == CLI_INIT)
1613 e->command = "stop when convenient";
1617 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1621 e->command = "core restart now";
1623 "Usage: core restart now\n"
1624 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1631 if (a->argc != e->args)
1632 return CLI_SHOWUSAGE;
1633 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1637 static char *handle_restart_now_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1639 char *res = handle_restart_now(e, cmd, a);
1640 if (cmd == CLI_INIT)
1641 e->command = "restart now";
1645 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1649 e->command = "core restart gracefully";
1651 "Usage: core restart gracefully\n"
1652 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1653 " restart when all active calls have ended.\n";
1659 if (a->argc != e->args)
1660 return CLI_SHOWUSAGE;
1661 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1665 static char *handle_restart_gracefully_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1667 char *res = handle_restart_gracefully(e, cmd, a);
1668 if (cmd == CLI_INIT)
1669 e->command = "restart gracefully";
1673 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1677 e->command = "core restart when convenient";
1679 "Usage: core restart when convenient\n"
1680 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1686 if (a->argc != e->args)
1687 return CLI_SHOWUSAGE;
1688 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
1689 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1693 static char *handle_restart_when_convenient_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1695 char *res = handle_restart_when_convenient(e, cmd, a);
1696 if (cmd == CLI_INIT)
1697 e->command = "restart when convenient";
1701 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1705 e->command = "core abort shutdown";
1707 "Usage: core abort shutdown\n"
1708 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1709 " call operations.\n";
1715 if (a->argc != e->args)
1716 return CLI_SHOWUSAGE;
1717 ast_cancel_shutdown();
1722 static char *handle_abort_shutdown_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1724 char *res = handle_abort_shutdown(e, cmd, a);
1725 if (cmd == CLI_INIT)
1726 e->command = "abort shutdown";
1730 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1736 "Usage: !<command>\n"
1737 " Executes a given shell command\n";
1745 static const char warranty_lines[] = {
1749 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
1750 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
1751 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
1752 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
1753 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
1754 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
1755 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
1756 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
1757 "REPAIR OR CORRECTION.\n"
1759 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
1760 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
1761 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
1762 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
1763 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
1764 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
1765 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
1766 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
1767 "POSSIBILITY OF SUCH DAMAGES.\n"
1770 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1774 e->command = "core show warranty";
1776 "Usage: core show warranty\n"
1777 " Shows the warranty (if any) for this copy of Asterisk.\n";
1783 ast_cli(a->fd, warranty_lines);
1788 static const char license_lines[] = {
1790 "This program is free software; you can redistribute it and/or modify\n"
1791 "it under the terms of the GNU General Public License version 2 as\n"
1792 "published by the Free Software Foundation.\n"
1794 "This program also contains components licensed under other licenses.\n"
1797 "This program is distributed in the hope that it will be useful,\n"
1798 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1799 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1800 "GNU General Public License for more details.\n"
1802 "You should have received a copy of the GNU General Public License\n"
1803 "along with this program; if not, write to the Free Software\n"
1804 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
1807 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1811 e->command = "core show license";
1813 "Usage: core show license\n"
1814 " Shows the license(s) for this copy of Asterisk.\n";
1820 ast_cli(a->fd, license_lines);
1825 #define ASTERISK_PROMPT "*CLI> "
1827 #define ASTERISK_PROMPT2 "%s*CLI> "
1829 /* deprecated cli entries */
1830 static struct ast_cli_entry cli_abort_shutdown_deprecated = AST_CLI_DEFINE(handle_abort_shutdown_deprecated, "Cancel a running shutdown.");
1831 static struct ast_cli_entry cli_stop_now_deprecated = AST_CLI_DEFINE(handle_stop_now_deprecated, "Shut down Asterisk immediately.");
1832 static struct ast_cli_entry cli_stop_gracefully_deprecated = AST_CLI_DEFINE(handle_stop_gracefully_deprecated, "Gracefully shut down Asterisk.");
1833 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.");
1834 static struct ast_cli_entry cli_restart_now_deprecated = AST_CLI_DEFINE(handle_restart_now_deprecated, "Restart Asterisk immediately.");
1835 static struct ast_cli_entry cli_restart_gracefully_deprecated = AST_CLI_DEFINE(handle_restart_gracefully_deprecated, "Restart Asterisk gracefully.");
1836 static struct ast_cli_entry cli_restart_when_convenient_deprecated = AST_CLI_DEFINE(handle_restart_when_convenient_deprecated, "Restart Asterisk at empty call volume.");
1837 /* end deprecated cli entries */
1839 static struct ast_cli_entry cli_asterisk[] = {
1840 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown", .deprecate_cmd = &cli_abort_shutdown_deprecated),
1841 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately", .deprecate_cmd = &cli_stop_now_deprecated),
1842 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk", .deprecate_cmd = &cli_stop_gracefully_deprecated),
1843 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume", .deprecate_cmd = &cli_stop_when_convenient_deprecated),
1844 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately", .deprecate_cmd = &cli_restart_now_deprecated),
1845 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully", .deprecate_cmd = &cli_restart_gracefully_deprecated),
1846 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume", .deprecate_cmd = &cli_restart_when_convenient_deprecated),
1847 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
1848 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
1849 AST_CLI_DEFINE(handle_version, "Display version info"),
1850 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
1851 #if !defined(LOW_MEMORY)
1852 AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
1853 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
1854 #if defined(HAVE_SYSINFO)
1855 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
1857 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
1858 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
1859 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
1860 #endif /* ! LOW_MEMORY */
1863 static int ast_el_read_char(EditLine *el, char *cp)
1867 struct pollfd fds[2];
1870 #define EL_BUF_SIZE 512
1871 char buf[EL_BUF_SIZE];
1875 fds[0].fd = ast_consock;
1876 fds[0].events = POLLIN;
1877 if (!ast_opt_exec) {
1878 fds[1].fd = STDIN_FILENO;
1879 fds[1].events = POLLIN;
1882 res = poll(fds, max, -1);
1886 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1890 if (!ast_opt_exec && fds[1].revents) {
1891 num_read = read(STDIN_FILENO, cp, 1);
1897 if (fds[0].revents) {
1898 res = read(ast_consock, buf, sizeof(buf) - 1);
1899 /* if the remote side disappears exit */
1901 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1902 if (!ast_opt_reconnect) {
1903 quit_handler(0, 0, 0, 0);
1906 int reconnects_per_second = 20;
1907 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1908 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
1909 if (ast_tryconnect()) {
1910 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1911 printf("%s", term_quit());
1914 fdprint(ast_consock, "logger mute silent");
1916 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
1919 usleep(1000000 / reconnects_per_second);
1921 if (tries >= 30 * reconnects_per_second) {
1922 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1923 quit_handler(0, 0, 0, 0);
1930 if (!ast_opt_exec && !lastpos)
1931 write(STDOUT_FILENO, "\r", 1);
1932 write(STDOUT_FILENO, buf, res);
1933 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
1945 static char *cli_prompt(EditLine *el)
1947 static char prompt[200];
1952 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1953 char *t = pfmt, *p = prompt;
1954 memset(prompt, 0, sizeof(prompt));
1955 while (*t != '\0' && *p < sizeof(prompt)) {
1957 char hostname[MAXHOSTNAMELEN]="";
1959 struct timeval ts = ast_tvnow();
1960 struct ast_tm tm = { 0, };
1964 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1968 case 'C': /* color */
1970 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1971 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1973 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1974 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1978 /* If the color has been reset correctly, then there's no need to reset it later */
1979 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
1981 case 'd': /* date */
1982 if (ast_localtime(&ts, &tm, NULL))
1983 ast_strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1985 case 'h': /* hostname */
1986 if (!gethostname(hostname, sizeof(hostname) - 1))
1987 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1989 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1991 case 'H': /* short hostname */
1992 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1993 for (i = 0; i < sizeof(hostname); i++) {
1994 if (hostname[i] == '.') {
1999 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
2001 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
2004 case 'l': /* load avg */
2006 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
2007 float avg1, avg2, avg3;
2008 int actproc, totproc, npid, which;
2009 fscanf(LOADAVG, "%f %f %f %d/%d %d",
2010 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
2011 if (sscanf(t, "%d", &which) == 1) {
2014 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
2017 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
2020 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
2023 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
2026 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
2033 case 's': /* Asterisk system name (from asterisk.conf) */
2034 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
2036 case 't': /* time */
2037 if (ast_localtime(&ts, &tm, NULL))
2038 ast_strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
2040 case '#': /* process console or remote? */
2041 if (!ast_opt_remote)
2042 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
2044 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
2046 case '%': /* literal % */
2047 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
2049 case '\0': /* % is last character - prevent bug */
2063 /* Force colors back to normal at end */
2064 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
2065 if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
2066 ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
2068 /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
2069 strncat(p, term_code, sizeof(term_code));
2072 } else if (remotehostname)
2073 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
2075 ast_copy_string(prompt, ASTERISK_PROMPT, sizeof(prompt));
2080 static char **ast_el_strtoarr(char *buf)
2082 char **match_list = NULL, **match_list_tmp, *retstr;
2083 size_t match_list_len;
2087 while ( (retstr = strsep(&buf, " ")) != NULL) {
2089 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2091 if (matches + 1 >= match_list_len) {
2092 match_list_len <<= 1;
2093 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2094 match_list = match_list_tmp;
2097 ast_free(match_list);
2098 return (char **) NULL;
2102 match_list[matches++] = ast_strdup(retstr);
2106 return (char **) NULL;
2108 if (matches >= match_list_len) {
2109 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2110 match_list = match_list_tmp;
2113 ast_free(match_list);
2114 return (char **) NULL;
2118 match_list[matches] = (char *) NULL;
2123 static int ast_el_sort_compare(const void *i1, const void *i2)
2127 s1 = ((char **)i1)[0];
2128 s2 = ((char **)i2)[0];
2130 return strcasecmp(s1, s2);
2133 static int ast_cli_display_match_list(char **matches, int len, int max)
2135 int i, idx, limit, count;
2136 int screenwidth = 0;
2137 int numoutput = 0, numoutputline = 0;
2139 screenwidth = ast_get_termcols(STDOUT_FILENO);
2141 /* find out how many entries can be put on one line, with two spaces between strings */
2142 limit = screenwidth / (max + 2);
2146 /* how many lines of output */
2147 count = len / limit;
2148 if (count * limit < len)
2153 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2155 for (; count > 0; count--) {
2157 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2159 /* Don't print dupes */
2160 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2162 ast_free(matches[idx]);
2163 matches[idx] = NULL;
2169 fprintf(stdout, "%-*s ", max, matches[idx]);
2170 ast_free(matches[idx]);
2171 matches[idx] = NULL;
2173 if (numoutputline > 0)
2174 fprintf(stdout, "\n");
2181 static char *cli_complete(EditLine *el, int ch)
2187 int retval = CC_ERROR;
2191 LineInfo *lf = (LineInfo *)el_line(el);
2193 *(char *)lf->cursor = '\0';
2194 ptr = (char *)lf->cursor;
2196 while (ptr > lf->buffer) {
2197 if (isspace(*ptr)) {
2205 len = lf->cursor - ptr;
2207 if (ast_opt_remote) {
2208 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2209 fdprint(ast_consock, buf);
2210 res = read(ast_consock, buf, sizeof(buf));
2212 nummatches = atoi(buf);
2214 if (nummatches > 0) {
2216 int mlen = 0, maxmbuf = 2048;
2217 /* Start with a 2048 byte buffer */
2218 if (!(mbuf = ast_malloc(maxmbuf)))
2219 return (char *)(CC_ERROR);
2220 snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2221 fdprint(ast_consock, buf);
2224 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2225 if (mlen + 1024 > maxmbuf) {
2226 /* Every step increment buffer 1024 bytes */
2228 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2229 return (char *)(CC_ERROR);
2231 /* Only read 1024 bytes at a time */
2232 res = read(ast_consock, mbuf + mlen, 1024);
2238 matches = ast_el_strtoarr(mbuf);
2241 matches = (char **) NULL;
2243 char **p, *oldbuf=NULL;
2245 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2246 for (p = matches; p && *p; p++) {
2247 if (!oldbuf || strcmp(*p,oldbuf))
2255 int matches_num, maxlen, match_len;
2257 if (matches[0][0] != '\0') {
2258 el_deletestr(el, (int) len);
2259 el_insertstr(el, matches[0]);
2260 retval = CC_REFRESH;
2263 if (nummatches == 1) {
2264 /* Found an exact match */
2265 el_insertstr(el, " ");
2266 retval = CC_REFRESH;
2268 /* Must be more than one match */
2269 for (i = 1, maxlen = 0; matches[i]; i++) {
2270 match_len = strlen(matches[i]);
2271 if (match_len > maxlen)
2274 matches_num = i - 1;
2275 if (matches_num >1) {
2276 fprintf(stdout, "\n");
2277 ast_cli_display_match_list(matches, nummatches, maxlen);
2278 retval = CC_REDISPLAY;
2280 el_insertstr(el," ");
2281 retval = CC_REFRESH;
2284 for (i = 0; matches[i]; i++)
2285 ast_free(matches[i]);
2289 return (char *)(long)retval;
2292 static int ast_el_initialize(void)
2295 char *editor = getenv("AST_EDITOR");
2299 if (el_hist != NULL)
2300 history_end(el_hist);
2302 el = el_init("asterisk", stdin, stdout, stderr);
2303 el_set(el, EL_PROMPT, cli_prompt);
2305 el_set(el, EL_EDITMODE, 1);
2306 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2307 el_hist = history_init();
2308 if (!el || !el_hist)
2311 /* setup history with 100 entries */
2312 history(el_hist, &ev, H_SETSIZE, 100);
2314 el_set(el, EL_HIST, history, el_hist);
2316 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2317 /* Bind <tab> to command completion */
2318 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2319 /* Bind ? to command completion */
2320 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2321 /* Bind ^D to redisplay */
2322 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2327 static int ast_el_add_history(char *buf)
2331 if (el_hist == NULL || el == NULL)
2332 ast_el_initialize();
2333 if (strlen(buf) > 256)
2335 return (history(el_hist, &ev, H_ENTER, buf));
2338 static int ast_el_write_history(char *filename)
2342 if (el_hist == NULL || el == NULL)
2343 ast_el_initialize();
2345 return (history(el_hist, &ev, H_SAVE, filename));
2348 static int ast_el_read_history(char *filename)
2354 if (el_hist == NULL || el == NULL)
2355 ast_el_initialize();
2357 if ((f = fopen(filename, "r")) == NULL)
2361 fgets(buf, sizeof(buf), f);
2362 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2364 if (ast_all_zeros(buf))
2366 if ((ret = ast_el_add_history(buf)) == -1)
2374 static void ast_remotecontrol(char * data)
2378 char filename[80] = "";
2384 char *stringp = NULL;
2389 read(ast_consock, buf, sizeof(buf));
2391 write(ast_consock, data, strlen(data) + 1);
2393 hostname = strsep(&stringp, "/");
2394 cpid = strsep(&stringp, "/");
2395 version = strsep(&stringp, "\n");
2397 version = "<Version Unknown>";
2399 strsep(&stringp, ".");
2405 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2406 fdprint(ast_consock, tmp);
2407 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2408 fdprint(ast_consock, tmp);
2410 fdprint(ast_consock, "logger mute silent");
2412 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2414 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2415 remotehostname = hostname;
2417 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2418 if (el_hist == NULL || el == NULL)
2419 ast_el_initialize();
2421 el_set(el, EL_GETCFN, ast_el_read_char);
2423 if (!ast_strlen_zero(filename))
2424 ast_el_read_history(filename);
2426 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2429 fds.fd = ast_consock;
2430 fds.events = POLLIN;
2432 while (poll(&fds, 1, 100) > 0)
2433 ast_el_read_char(el, &tempchar);
2437 ebuf = (char *)el_gets(el, &num);
2439 if (!ebuf && write(1, "", 1) < 0)
2442 if (!ast_strlen_zero(ebuf)) {
2443 if (ebuf[strlen(ebuf)-1] == '\n')
2444 ebuf[strlen(ebuf)-1] = '\0';
2445 if (!remoteconsolehandler(ebuf)) {
2446 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2448 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2454 printf("\nDisconnected from Asterisk server\n");
2457 static int show_version(void)
2459 printf("Asterisk %s\n", ast_get_version());
2463 static int show_cli_help(void) {
2464 printf("Asterisk %s, Copyright (C) 1999 - 2008, Digium, Inc. and others.\n", ast_get_version());
2465 printf("Usage: asterisk [OPTIONS]\n");
2466 printf("Valid Options:\n");
2467 printf(" -V Display version number and exit\n");
2468 printf(" -C <configfile> Use an alternate configuration file\n");
2469 printf(" -G <group> Run as a group other than the caller\n");
2470 printf(" -U <user> Run as a user other than the caller\n");
2471 printf(" -c Provide console CLI\n");
2472 printf(" -d Enable extra debugging\n");
2473 #if HAVE_WORKING_FORK
2474 printf(" -f Do not fork\n");
2475 printf(" -F Always fork\n");
2477 printf(" -g Dump core in case of a crash\n");
2478 printf(" -h This help screen\n");
2479 printf(" -i Initialize crypto keys at startup\n");
2480 printf(" -I Enable internal timing if Zaptel timer is available\n");
2481 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2482 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2483 printf(" -m Mute debugging and console output on the console\n");
2484 printf(" -n Disable console colorization\n");
2485 printf(" -p Run as pseudo-realtime thread\n");
2486 printf(" -q Quiet mode (suppress output)\n");
2487 printf(" -r Connect to Asterisk on this machine\n");
2488 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2489 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2490 printf(" belong after they are done\n");
2491 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2492 printf(" of output to the CLI\n");
2493 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2494 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2495 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
2500 static void ast_readconfig(void)
2502 struct ast_config *cfg;
2503 struct ast_variable *v;
2504 char *config = DEFAULT_CONFIG_FILE;
2505 char hostname[MAXHOSTNAMELEN] = "";
2506 struct ast_flags config_flags = { 0 };
2508 unsigned int dbdir:1;
2509 unsigned int keydir:1;
2512 if (ast_opt_override_config) {
2513 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
2515 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2517 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
2519 /* init with buildtime config */
2520 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2521 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2522 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2523 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
2524 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2525 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2526 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2527 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2528 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2529 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2530 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2531 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2532 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2534 /* no asterisk.conf? no problem, use buildtime config! */
2539 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2540 if (!strcasecmp(v->name, "astctlpermissions"))
2541 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2542 else if (!strcasecmp(v->name, "astctlowner"))
2543 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2544 else if (!strcasecmp(v->name, "astctlgroup"))
2545 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2546 else if (!strcasecmp(v->name, "astctl"))
2547 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2550 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2551 if (!strcasecmp(v->name, "astetcdir")) {
2552 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2553 } else if (!strcasecmp(v->name, "astspooldir")) {
2554 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2555 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
2556 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2557 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2559 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2560 } else if (!strcasecmp(v->name, "astdbdir")) {
2561 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2563 } else if (!strcasecmp(v->name, "astdatadir")) {
2564 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2566 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2567 } else if (!strcasecmp(v->name, "astkeydir")) {
2568 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2570 } else if (!strcasecmp(v->name, "astlogdir")) {
2571 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2572 } else if (!strcasecmp(v->name, "astagidir")) {
2573 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2574 } else if (!strcasecmp(v->name, "astrundir")) {
2575 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2576 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2577 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2578 } else if (!strcasecmp(v->name, "astmoddir")) {
2579 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2583 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2584 /* verbose level (-v at startup) */
2585 if (!strcasecmp(v->name, "verbose")) {
2586 option_verbose = atoi(v->value);
2587 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2588 } else if (!strcasecmp(v->name, "timestamp")) {
2589 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2590 /* whether or not to support #exec in config files */
2591 } else if (!strcasecmp(v->name, "execincludes")) {
2592 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2593 /* debug level (-d at startup) */
2594 } else if (!strcasecmp(v->name, "debug")) {
2596 if (sscanf(v->value, "%d", &option_debug) != 1) {
2597 option_debug = ast_true(v->value);
2599 #if HAVE_WORKING_FORK
2600 /* Disable forking (-f at startup) */
2601 } else if (!strcasecmp(v->name, "nofork")) {
2602 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2603 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2604 } else if (!strcasecmp(v->name, "alwaysfork")) {
2605 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2607 /* Run quietly (-q at startup ) */
2608 } else if (!strcasecmp(v->name, "quiet")) {
2609 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2610 /* Run as console (-c at startup, implies nofork) */
2611 } else if (!strcasecmp(v->name, "console")) {
2612 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2613 /* Run with high priority if the O/S permits (-p at startup) */
2614 } else if (!strcasecmp(v->name, "highpriority")) {
2615 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2616 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2617 } else if (!strcasecmp(v->name, "initcrypto")) {
2618 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2619 /* Disable ANSI colors for console (-c at startup) */
2620 } else if (!strcasecmp(v->name, "nocolor")) {
2621 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2622 /* Disable some usage warnings for picky people :p */
2623 } else if (!strcasecmp(v->name, "dontwarn")) {
2624 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2625 /* Dump core in case of crash (-g) */
2626 } else if (!strcasecmp(v->name, "dumpcore")) {
2627 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2628 /* Cache recorded sound files to another directory during recording */
2629 } else if (!strcasecmp(v->name, "cache_record_files")) {
2630 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2631 /* Specify cache directory */
2632 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2633 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2634 /* Build transcode paths via SLINEAR, instead of directly */
2635 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2636 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2637 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2638 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2639 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2640 /* Enable internal timing */
2641 } else if (!strcasecmp(v->name, "internal_timing")) {
2642 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2643 } else if (!strcasecmp(v->name, "maxcalls")) {
2644 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2645 option_maxcalls = 0;
2647 } else if (!strcasecmp(v->name, "maxload")) {
2650 if (getloadavg(test, 1) == -1) {
2651 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2652 option_maxload = 0.0;
2653 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2654 option_maxload = 0.0;
2656 /* Set the maximum amount of open files */
2657 } else if (!strcasecmp(v->name, "maxfiles")) {
2658 option_maxfiles = atoi(v->value);
2659 set_ulimit(option_maxfiles);
2660 /* What user to run as */
2661 } else if (!strcasecmp(v->name, "runuser")) {
2662 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
2663 /* What group to run as */
2664 } else if (!strcasecmp(v->name, "rungroup")) {
2665 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
2666 } else if (!strcasecmp(v->name, "systemname")) {
2667 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
2668 } else if (!strcasecmp(v->name, "autosystemname")) {
2669 if (ast_true(v->value)) {
2670 if (!gethostname(hostname, sizeof(hostname) - 1))
2671 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
2673 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2674 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
2676 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2679 } else if (!strcasecmp(v->name, "languageprefix")) {
2680 ast_language_is_prefix = ast_true(v->value);
2681 } else if (!strcasecmp(v->name, "lockmode")) {
2682 if (!strcasecmp(v->value, "lockfile")) {
2683 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2684 } else if (!strcasecmp(v->value, "flock")) {
2685 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
2687 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
2688 "defaulting to 'lockfile'\n", v->value);
2689 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2691 #if defined(HAVE_SYSINFO)
2692 } else if (!strcasecmp(v->name, "minmemfree")) {
2693 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
2694 * if the amount of free memory falls below this watermark */
2695 if ((sscanf(v->value, "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2696 option_minmemfree = 0;
2701 ast_config_destroy(cfg);
2704 static void *monitor_sig_flags(void *unused)
2707 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2710 if (sig_flags.need_reload) {
2711 sig_flags.need_reload = 0;
2712 ast_module_reload(NULL);
2714 if (sig_flags.need_quit) {
2715 sig_flags.need_quit = 0;
2716 quit_handler(0, 0, 1, 0);
2718 read(sig_alert_pipe[0], &a, sizeof(a));
2724 static void *canary_thread(void *unused)
2726 struct stat canary_stat;
2729 /* Give the canary time to sing */
2733 stat(canary_filename, &canary_stat);
2735 if (tv.tv_sec > canary_stat.st_mtime + 60) {
2736 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");
2737 ast_set_priority(0);
2741 /* Check the canary once a minute */
2746 /* Used by libc's atexit(3) function */
2747 static void canary_exit(void)
2750 kill(canary_pid, SIGKILL);
2753 static void run_startup_commands(void)
2756 struct ast_config *cfg;
2757 struct ast_flags cfg_flags = { 0 };
2758 struct ast_variable *v;
2760 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
2763 fd = open("/dev/null", O_RDWR);
2767 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
2768 if (ast_true(v->value))
2769 ast_cli_command(fd, v->name);
2773 ast_config_destroy(cfg);
2776 int main(int argc, char *argv[])
2779 char filename[80] = "";
2780 char hostname[MAXHOSTNAMELEN] = "";
2789 const char *runuser = NULL, *rungroup = NULL;
2790 char *remotesock = NULL;
2792 /* Remember original args for restart */
2793 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2794 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2795 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2797 for (x = 0; x < argc; x++)
2804 /* if the progname is rasterisk consider it a remote console */
2805 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2806 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2808 if (gethostname(hostname, sizeof(hostname)-1))
2809 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2810 ast_mainpid = getpid();
2814 ast_builtins_init();
2819 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2820 /* Check for options */
2821 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:s:")) != -1) {
2823 #if defined(HAVE_SYSINFO)
2825 if ((sscanf(&optarg[1], "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2826 option_minmemfree = 0;
2830 #if HAVE_WORKING_FORK
2832 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2835 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2840 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2843 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2846 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2849 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2852 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2855 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2859 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2862 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2865 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2866 option_maxcalls = 0;
2869 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2870 option_maxload = 0.0;
2873 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2876 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2879 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2882 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2883 xarg = ast_strdupa(optarg);
2886 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
2887 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2890 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2893 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2896 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2905 runuser = ast_strdupa(optarg);
2908 rungroup = ast_strdupa(optarg);
2911 remotesock = ast_strdupa(optarg);
2918 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2919 ast_register_verbose(console_verboser);
2923 if (ast_opt_console && !option_verbose)
2924 ast_verbose("[ Booting...\n");
2926 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2927 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2928 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2931 /* For remote connections, change the name of the remote connection.
2932 * We do this for the benefit of init scripts (which need to know if/when
2933 * the main asterisk process has died yet). */
2934 if (ast_opt_remote) {
2935 strcpy(argv[0], "rasterisk");
2936 for (x = 1; x < argc; x++) {
2937 argv[x] = argv[0] + 10;
2941 if (ast_opt_console && !option_verbose)
2942 ast_verbose("[ Reading Master Configuration ]\n");
2945 if (ast_opt_remote && remotesock != NULL)
2946 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
2948 if (!ast_language_is_prefix && !ast_opt_remote)
2949 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");
2951 if (ast_opt_dump_core) {
2953 memset(&l, 0, sizeof(l));
2954 l.rlim_cur = RLIM_INFINITY;
2955 l.rlim_max = RLIM_INFINITY;
2956 if (setrlimit(RLIMIT_CORE, &l)) {
2957 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2961 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2962 rungroup = ast_config_AST_RUN_GROUP;
2963 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2964 runuser = ast_config_AST_RUN_USER;
2966 /* Must install this signal handler up here to ensure that if the canary
2967 * fails to execute that it doesn't kill the Asterisk process.
2969 signal(SIGCHLD, child_handler);
2974 ast_set_priority(ast_opt_high_priority);
2975 if (ast_opt_high_priority) {
2976 snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
2978 canary_pid = fork();
2979 if (canary_pid == 0) {
2980 char canary_binary[128], *lastslash;
2983 /* Reset signal handler */
2984 signal(SIGCHLD, SIG_DFL);
2986 for (fd = 0; fd < 100; fd++)
2989 execlp("astcanary", "astcanary", canary_filename, (char *)NULL);
2991 /* If not found, try the same path as used to execute asterisk */
2992 ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
2993 if ((lastslash = strrchr(canary_binary, '/'))) {
2994 ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
2995 execl(canary_binary, "astcanary", canary_filename, (char *)NULL);
2998 /* Should never happen */
3000 } else if (canary_pid > 0) {
3001 pthread_t dont_care;
3002 ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
3005 /* Kill the canary when we exit */
3006 atexit(canary_exit);
3010 if (isroot && rungroup) {
3012 gr = getgrnam(rungroup);
3014 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
3017 if (setgid(gr->gr_gid)) {
3018 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
3021 if (setgroups(0, NULL)) {
3022 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
3026 ast_verbose("Running as group '%s'\n", rungroup);
3029 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
3032 #endif /* HAVE_CAP */
3034 pw = getpwnam(runuser);
3036 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
3040 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
3041 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
3044 #endif /* HAVE_CAP */
3045 if (!isroot && pw->pw_uid != geteuid()) {
3046 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
3050 if (setgid(pw->pw_gid)) {
3051 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
3054 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
3055 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
3059 if (setuid(pw->pw_uid)) {
3060 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
3064 ast_verbose("Running as user '%s'\n", runuser);
3069 cap = cap_from_text("cap_net_admin=ep");
3071 if (cap_set_proc(cap))
3072 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
3075 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
3077 #endif /* HAVE_CAP */
3080 #endif /* __CYGWIN__ */
3083 if (geteuid() && ast_opt_dump_core) {
3084 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
3085 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
3091 printf("%s", term_end());
3094 if (ast_opt_console && !option_verbose)
3095 ast_verbose("[ Initializing Custom Configuration Options ]\n");
3096 /* custom config setup */
3097 register_config_cli();
3100 if (ast_opt_console) {
3101 if (el_hist == NULL || el == NULL)
3102 ast_el_initialize();
3104 if (!ast_strlen_zero(filename))
3105 ast_el_read_history(filename);
3108 if (ast_tryconnect()) {