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" \
146 "NOTE: This is a development version of Asterisk, and should not be used in\n" \
147 "production installations.\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, " Max. calls: %d (Current %d)\n", option_maxcalls, ast_active_channels());
402 ast_cli(a->fd, " Max. calls: Not set\n");
404 ast_cli(a->fd, " Max. open file handles: %d\n", option_maxfiles);
406 ast_cli(a->fd, " Max. 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, " Max load avg: %lf\n", option_maxload);
410 #if defined(HAVE_SYSINFO)
411 ast_cli(a->fd, " Min 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(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)
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(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))
2066 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
2068 strncat(p, term_code, sizeof(term_code));
2070 } else if (remotehostname)
2071 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
2073 ast_copy_string(prompt, ASTERISK_PROMPT, sizeof(prompt));
2078 static char **ast_el_strtoarr(char *buf)
2080 char **match_list = NULL, **match_list_tmp, *retstr;
2081 size_t match_list_len;
2085 while ( (retstr = strsep(&buf, " ")) != NULL) {
2087 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2089 if (matches + 1 >= match_list_len) {
2090 match_list_len <<= 1;
2091 if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2092 match_list = match_list_tmp;
2095 ast_free(match_list);
2096 return (char **) NULL;
2100 match_list[matches++] = ast_strdup(retstr);
2104 return (char **) NULL;
2106 if (matches >= match_list_len) {
2107 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2108 match_list = match_list_tmp;
2111 ast_free(match_list);
2112 return (char **) NULL;
2116 match_list[matches] = (char *) NULL;
2121 static int ast_el_sort_compare(const void *i1, const void *i2)
2125 s1 = ((char **)i1)[0];
2126 s2 = ((char **)i2)[0];
2128 return strcasecmp(s1, s2);
2131 static int ast_cli_display_match_list(char **matches, int len, int max)
2133 int i, idx, limit, count;
2134 int screenwidth = 0;
2135 int numoutput = 0, numoutputline = 0;
2137 screenwidth = ast_get_termcols(STDOUT_FILENO);
2139 /* find out how many entries can be put on one line, with two spaces between strings */
2140 limit = screenwidth / (max + 2);
2144 /* how many lines of output */
2145 count = len / limit;
2146 if (count * limit < len)
2151 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2153 for (; count > 0; count--) {
2155 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2157 /* Don't print dupes */
2158 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2160 ast_free(matches[idx]);
2161 matches[idx] = NULL;
2167 fprintf(stdout, "%-*s ", max, matches[idx]);
2168 ast_free(matches[idx]);
2169 matches[idx] = NULL;
2171 if (numoutputline > 0)
2172 fprintf(stdout, "\n");
2179 static char *cli_complete(EditLine *el, int ch)
2185 int retval = CC_ERROR;
2189 LineInfo *lf = (LineInfo *)el_line(el);
2191 *(char *)lf->cursor = '\0';
2192 ptr = (char *)lf->cursor;
2194 while (ptr > lf->buffer) {
2195 if (isspace(*ptr)) {
2203 len = lf->cursor - ptr;
2205 if (ast_opt_remote) {
2206 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2207 fdprint(ast_consock, buf);
2208 res = read(ast_consock, buf, sizeof(buf));
2210 nummatches = atoi(buf);
2212 if (nummatches > 0) {
2214 int mlen = 0, maxmbuf = 2048;
2215 /* Start with a 2048 byte buffer */
2216 if (!(mbuf = ast_malloc(maxmbuf)))
2217 return (char *)(CC_ERROR);
2218 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2219 fdprint(ast_consock, buf);
2222 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2223 if (mlen + 1024 > maxmbuf) {
2224 /* Every step increment buffer 1024 bytes */
2226 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2227 return (char *)(CC_ERROR);
2229 /* Only read 1024 bytes at a time */
2230 res = read(ast_consock, mbuf + mlen, 1024);
2236 matches = ast_el_strtoarr(mbuf);
2239 matches = (char **) NULL;
2241 char **p, *oldbuf=NULL;
2243 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2244 for (p = matches; p && *p; p++) {
2245 if (!oldbuf || strcmp(*p,oldbuf))
2253 int matches_num, maxlen, match_len;
2255 if (matches[0][0] != '\0') {
2256 el_deletestr(el, (int) len);
2257 el_insertstr(el, matches[0]);
2258 retval = CC_REFRESH;
2261 if (nummatches == 1) {
2262 /* Found an exact match */
2263 el_insertstr(el, " ");
2264 retval = CC_REFRESH;
2266 /* Must be more than one match */
2267 for (i = 1, maxlen = 0; matches[i]; i++) {
2268 match_len = strlen(matches[i]);
2269 if (match_len > maxlen)
2272 matches_num = i - 1;
2273 if (matches_num >1) {
2274 fprintf(stdout, "\n");
2275 ast_cli_display_match_list(matches, nummatches, maxlen);
2276 retval = CC_REDISPLAY;
2278 el_insertstr(el," ");
2279 retval = CC_REFRESH;
2282 for (i = 0; matches[i]; i++)
2283 ast_free(matches[i]);
2287 return (char *)(long)retval;
2290 static int ast_el_initialize(void)
2293 char *editor = getenv("AST_EDITOR");
2297 if (el_hist != NULL)
2298 history_end(el_hist);
2300 el = el_init("asterisk", stdin, stdout, stderr);
2301 el_set(el, EL_PROMPT, cli_prompt);
2303 el_set(el, EL_EDITMODE, 1);
2304 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2305 el_hist = history_init();
2306 if (!el || !el_hist)
2309 /* setup history with 100 entries */
2310 history(el_hist, &ev, H_SETSIZE, 100);
2312 el_set(el, EL_HIST, history, el_hist);
2314 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2315 /* Bind <tab> to command completion */
2316 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2317 /* Bind ? to command completion */
2318 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2319 /* Bind ^D to redisplay */
2320 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2325 static int ast_el_add_history(char *buf)
2329 if (el_hist == NULL || el == NULL)
2330 ast_el_initialize();
2331 if (strlen(buf) > 256)
2333 return (history(el_hist, &ev, H_ENTER, buf));
2336 static int ast_el_write_history(char *filename)
2340 if (el_hist == NULL || el == NULL)
2341 ast_el_initialize();
2343 return (history(el_hist, &ev, H_SAVE, filename));
2346 static int ast_el_read_history(char *filename)
2352 if (el_hist == NULL || el == NULL)
2353 ast_el_initialize();
2355 if ((f = fopen(filename, "r")) == NULL)
2359 fgets(buf, sizeof(buf), f);
2360 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2362 if (ast_all_zeros(buf))
2364 if ((ret = ast_el_add_history(buf)) == -1)
2372 static void ast_remotecontrol(char * data)
2376 char filename[80] = "";
2382 char *stringp = NULL;
2387 read(ast_consock, buf, sizeof(buf));
2389 write(ast_consock, data, strlen(data) + 1);
2391 hostname = strsep(&stringp, "/");
2392 cpid = strsep(&stringp, "/");
2393 version = strsep(&stringp, "\n");
2395 version = "<Version Unknown>";
2397 strsep(&stringp, ".");
2403 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2404 fdprint(ast_consock, tmp);
2405 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2406 fdprint(ast_consock, tmp);
2408 fdprint(ast_consock, "logger mute silent");
2410 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2412 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2413 remotehostname = hostname;
2415 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2416 if (el_hist == NULL || el == NULL)
2417 ast_el_initialize();
2419 el_set(el, EL_GETCFN, ast_el_read_char);
2421 if (!ast_strlen_zero(filename))
2422 ast_el_read_history(filename);
2424 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2427 fds.fd = ast_consock;
2428 fds.events = POLLIN;
2430 while (poll(&fds, 1, 100) > 0)
2431 ast_el_read_char(el, &tempchar);
2435 ebuf = (char *)el_gets(el, &num);
2437 if (!ebuf && write(1, "", 1) < 0)
2440 if (!ast_strlen_zero(ebuf)) {
2441 if (ebuf[strlen(ebuf)-1] == '\n')
2442 ebuf[strlen(ebuf)-1] = '\0';
2443 if (!remoteconsolehandler(ebuf)) {
2444 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2446 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2452 printf("\nDisconnected from Asterisk server\n");
2455 static int show_version(void)
2457 printf("Asterisk %s\n", ast_get_version());
2461 static int show_cli_help(void) {
2462 printf("Asterisk %s, Copyright (C) 1999 - 2008, Digium, Inc. and others.\n", ast_get_version());
2463 printf("Usage: asterisk [OPTIONS]\n");
2464 printf("Valid Options:\n");
2465 printf(" -V Display version number and exit\n");
2466 printf(" -C <configfile> Use an alternate configuration file\n");
2467 printf(" -G <group> Run as a group other than the caller\n");
2468 printf(" -U <user> Run as a user other than the caller\n");
2469 printf(" -c Provide console CLI\n");
2470 printf(" -d Enable extra debugging\n");
2471 #if HAVE_WORKING_FORK
2472 printf(" -f Do not fork\n");
2473 printf(" -F Always fork\n");
2475 printf(" -g Dump core in case of a crash\n");
2476 printf(" -h This help screen\n");
2477 printf(" -i Initialize crypto keys at startup\n");
2478 printf(" -I Enable internal timing if Zaptel timer is available\n");
2479 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2480 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2481 printf(" -m Mute debugging and console output on the console\n");
2482 printf(" -n Disable console colorization\n");
2483 printf(" -p Run as pseudo-realtime thread\n");
2484 printf(" -q Quiet mode (suppress output)\n");
2485 printf(" -r Connect to Asterisk on this machine\n");
2486 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2487 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2488 printf(" belong after they are done\n");
2489 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2490 printf(" of output to the CLI\n");
2491 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2492 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2493 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
2498 static void ast_readconfig(void)
2500 struct ast_config *cfg;
2501 struct ast_variable *v;
2502 char *config = DEFAULT_CONFIG_FILE;
2503 char hostname[MAXHOSTNAMELEN] = "";
2504 struct ast_flags config_flags = { 0 };
2506 unsigned int dbdir:1;
2507 unsigned int keydir:1;
2510 if (ast_opt_override_config) {
2511 cfg = ast_config_load(ast_config_AST_CONFIG_FILE, config_flags);
2513 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2515 cfg = ast_config_load(config, config_flags);
2517 /* init with buildtime config */
2518 ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2519 ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2520 ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2521 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir) - 1, "%s/monitor", cfg_paths.spool_dir);
2522 ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2523 ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2524 ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2525 ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2526 ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2527 ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2528 ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2529 ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2530 ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2532 /* no asterisk.conf? no problem, use buildtime config! */
2537 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2538 if (!strcasecmp(v->name, "astctlpermissions"))
2539 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2540 else if (!strcasecmp(v->name, "astctlowner"))
2541 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2542 else if (!strcasecmp(v->name, "astctlgroup"))
2543 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2544 else if (!strcasecmp(v->name, "astctl"))
2545 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2548 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2549 if (!strcasecmp(v->name, "astetcdir")) {
2550 ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2551 } else if (!strcasecmp(v->name, "astspooldir")) {
2552 ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2553 snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir) - 1, "%s/monitor", v->value);
2554 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2555 ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2557 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2558 } else if (!strcasecmp(v->name, "astdbdir")) {
2559 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2561 } else if (!strcasecmp(v->name, "astdatadir")) {
2562 ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2564 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2565 } else if (!strcasecmp(v->name, "astkeydir")) {
2566 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2568 } else if (!strcasecmp(v->name, "astlogdir")) {
2569 ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2570 } else if (!strcasecmp(v->name, "astagidir")) {
2571 ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2572 } else if (!strcasecmp(v->name, "astrundir")) {
2573 snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2574 snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2575 ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2576 } else if (!strcasecmp(v->name, "astmoddir")) {
2577 ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2581 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2582 /* verbose level (-v at startup) */
2583 if (!strcasecmp(v->name, "verbose")) {
2584 option_verbose = atoi(v->value);
2585 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2586 } else if (!strcasecmp(v->name, "timestamp")) {
2587 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2588 /* whether or not to support #exec in config files */
2589 } else if (!strcasecmp(v->name, "execincludes")) {
2590 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2591 /* debug level (-d at startup) */
2592 } else if (!strcasecmp(v->name, "debug")) {
2594 if (sscanf(v->value, "%d", &option_debug) != 1) {
2595 option_debug = ast_true(v->value);
2597 #if HAVE_WORKING_FORK
2598 /* Disable forking (-f at startup) */
2599 } else if (!strcasecmp(v->name, "nofork")) {
2600 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2601 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2602 } else if (!strcasecmp(v->name, "alwaysfork")) {
2603 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2605 /* Run quietly (-q at startup ) */
2606 } else if (!strcasecmp(v->name, "quiet")) {
2607 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2608 /* Run as console (-c at startup, implies nofork) */
2609 } else if (!strcasecmp(v->name, "console")) {
2610 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2611 /* Run with high priority if the O/S permits (-p at startup) */
2612 } else if (!strcasecmp(v->name, "highpriority")) {
2613 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2614 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2615 } else if (!strcasecmp(v->name, "initcrypto")) {
2616 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2617 /* Disable ANSI colors for console (-c at startup) */
2618 } else if (!strcasecmp(v->name, "nocolor")) {
2619 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2620 /* Disable some usage warnings for picky people :p */
2621 } else if (!strcasecmp(v->name, "dontwarn")) {
2622 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2623 /* Dump core in case of crash (-g) */
2624 } else if (!strcasecmp(v->name, "dumpcore")) {
2625 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2626 /* Cache recorded sound files to another directory during recording */
2627 } else if (!strcasecmp(v->name, "cache_record_files")) {
2628 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2629 /* Specify cache directory */
2630 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2631 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2632 /* Build transcode paths via SLINEAR, instead of directly */
2633 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2634 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2635 /* Transmit SLINEAR silence while a channel is being recorded */
2636 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2637 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2638 /* Enable internal timing */
2639 } else if (!strcasecmp(v->name, "internal_timing")) {
2640 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2641 } else if (!strcasecmp(v->name, "maxcalls")) {
2642 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2643 option_maxcalls = 0;
2645 } else if (!strcasecmp(v->name, "maxload")) {
2648 if (getloadavg(test, 1) == -1) {
2649 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2650 option_maxload = 0.0;
2651 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2652 option_maxload = 0.0;
2654 /* Set the maximum amount of open files */
2655 } else if (!strcasecmp(v->name, "maxfiles")) {
2656 option_maxfiles = atoi(v->value);
2657 set_ulimit(option_maxfiles);
2658 /* What user to run as */
2659 } else if (!strcasecmp(v->name, "runuser")) {
2660 ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
2661 /* What group to run as */
2662 } else if (!strcasecmp(v->name, "rungroup")) {
2663 ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
2664 } else if (!strcasecmp(v->name, "systemname")) {
2665 ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
2666 } else if (!strcasecmp(v->name, "autosystemname")) {
2667 if (ast_true(v->value)) {
2668 if (!gethostname(hostname, sizeof(hostname) - 1))
2669 ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
2671 if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2672 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
2674 ast_log(LOG_ERROR, "Cannot obtain hostname for this system. Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2677 } else if (!strcasecmp(v->name, "languageprefix")) {
2678 ast_language_is_prefix = ast_true(v->value);
2679 } else if (!strcasecmp(v->name, "lockmode")) {
2680 if (!strcasecmp(v->value, "lockfile")) {
2681 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2682 } else if (!strcasecmp(v->value, "flock")) {
2683 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
2685 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
2686 "defaulting to 'lockfile'\n", v->value);
2687 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2689 #if defined(HAVE_SYSINFO)
2690 } else if (!strcasecmp(v->name, "minmemfree")) {
2691 /* specify the minimum amount of free memory to retain. Asterisk should stop accepting new calls
2692 * if the amount of free memory falls below this watermark */
2693 if ((sscanf(v->value, "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2694 option_minmemfree = 0;
2699 ast_config_destroy(cfg);
2702 static void *monitor_sig_flags(void *unused)
2705 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2708 if (sig_flags.need_reload) {
2709 sig_flags.need_reload = 0;
2710 ast_module_reload(NULL);
2712 if (sig_flags.need_quit) {
2713 sig_flags.need_quit = 0;
2714 quit_handler(0, 0, 1, 0);
2716 read(sig_alert_pipe[0], &a, sizeof(a));
2722 static void *canary_thread(void *unused)
2724 struct stat canary_stat;
2727 /* Give the canary time to sing */
2731 stat(canary_filename, &canary_stat);
2733 if (tv.tv_sec > canary_stat.st_mtime + 60) {
2734 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");
2735 ast_set_priority(0);
2739 /* Check the canary once a minute */
2744 /* Used by libc's atexit(3) function */
2745 static void canary_exit(void)
2748 kill(canary_pid, SIGKILL);
2751 static void run_startup_commands(void)
2754 struct ast_config *cfg;
2755 struct ast_flags cfg_flags = { 0 };
2756 struct ast_variable *v;
2758 if (!(cfg = ast_config_load("cli.conf", cfg_flags)))
2761 fd = open("/dev/null", O_RDWR);
2765 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
2766 if (ast_true(v->value))
2767 ast_cli_command(fd, v->name);
2771 ast_config_destroy(cfg);
2774 int main(int argc, char *argv[])
2777 char filename[80] = "";
2778 char hostname[MAXHOSTNAMELEN] = "";
2787 const char *runuser = NULL, *rungroup = NULL;
2788 char *remotesock = NULL;
2790 /* Remember original args for restart */
2791 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2792 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2793 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2795 for (x = 0; x < argc; x++)
2802 /* if the progname is rasterisk consider it a remote console */
2803 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2804 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2806 if (gethostname(hostname, sizeof(hostname)-1))
2807 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2808 ast_mainpid = getpid();
2812 ast_builtins_init();
2817 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2818 /* Check for options */
2819 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:s:")) != -1) {
2821 #if defined(HAVE_SYSINFO)
2823 if ((sscanf(&optarg[1], "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2824 option_minmemfree = 0;
2828 #if HAVE_WORKING_FORK
2830 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2833 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2838 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2841 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2844 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2847 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2850 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2853 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2857 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2860 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2863 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2864 option_maxcalls = 0;
2867 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2868 option_maxload = 0.0;
2871 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2874 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2877 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2880 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2881 xarg = ast_strdupa(optarg);
2884 ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
2885 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2888 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2891 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2894 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2903 runuser = ast_strdupa(optarg);
2906 rungroup = ast_strdupa(optarg);
2909 remotesock = ast_strdupa(optarg);
2916 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2917 ast_register_verbose(console_verboser);
2921 if (ast_opt_console && !option_verbose)
2922 ast_verbose("[ Booting...\n");
2924 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2925 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2926 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2929 /* For remote connections, change the name of the remote connection.
2930 * We do this for the benefit of init scripts (which need to know if/when
2931 * the main asterisk process has died yet). */
2932 if (ast_opt_remote) {
2933 strcpy(argv[0], "rasterisk");
2934 for (x = 1; x < argc; x++) {
2935 argv[x] = argv[0] + 10;
2939 if (ast_opt_console && !option_verbose)
2940 ast_verbose("[ Reading Master Configuration ]\n");
2943 if (ast_opt_remote && remotesock != NULL)
2944 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
2946 if (!ast_language_is_prefix && !ast_opt_remote)
2947 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");
2949 if (ast_opt_dump_core) {
2951 memset(&l, 0, sizeof(l));
2952 l.rlim_cur = RLIM_INFINITY;
2953 l.rlim_max = RLIM_INFINITY;
2954 if (setrlimit(RLIMIT_CORE, &l)) {
2955 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2959 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2960 rungroup = ast_config_AST_RUN_GROUP;
2961 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2962 runuser = ast_config_AST_RUN_USER;
2964 /* Must install this signal handler up here to ensure that if the canary
2965 * fails to execute that it doesn't kill the Asterisk process.
2967 signal(SIGCHLD, child_handler);
2972 ast_set_priority(ast_opt_high_priority);
2973 if (ast_opt_high_priority) {
2974 snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
2976 canary_pid = fork();
2977 if (canary_pid == 0) {
2978 char canary_binary[128], *lastslash;
2981 /* Reset signal handler */
2982 signal(SIGCHLD, SIG_DFL);
2984 for (fd = 0; fd < 100; fd++)
2987 execlp("astcanary", "astcanary", canary_filename, (char *)NULL);
2989 /* If not found, try the same path as used to execute asterisk */
2990 ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
2991 if ((lastslash = strrchr(canary_binary, '/'))) {
2992 ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
2993 execl(canary_binary, "astcanary", canary_filename, (char *)NULL);
2996 /* Should never happen */
2998 } else if (canary_pid > 0) {
2999 pthread_t dont_care;
3000 ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
3003 /* Kill the canary when we exit */
3004 atexit(canary_exit);
3008 if (isroot && rungroup) {
3010 gr = getgrnam(rungroup);
3012 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
3015 if (setgid(gr->gr_gid)) {
3016 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
3019 if (setgroups(0, NULL)) {
3020 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
3024 ast_verbose("Running as group '%s'\n", rungroup);
3027 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
3030 #endif /* HAVE_CAP */
3032 pw = getpwnam(runuser);
3034 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
3038 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
3039 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
3042 #endif /* HAVE_CAP */
3043 if (!isroot && pw->pw_uid != geteuid()) {
3044 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
3048 if (setgid(pw->pw_gid)) {
3049 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
3052 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
3053 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
3057 if (setuid(pw->pw_uid)) {
3058 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
3062 ast_verbose("Running as user '%s'\n", runuser);
3067 cap = cap_from_text("cap_net_admin=ep");
3069 if (cap_set_proc(cap))
3070 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
3073 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
3075 #endif /* HAVE_CAP */
3078 #endif /* __CYGWIN__ */
3081 if (geteuid() && ast_opt_dump_core) {
3082 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
3083 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
3092 if (ast_opt_console && !option_verbose)
3093 ast_verbose("[ Initializing Custom Configuration Options ]\n");
3094 /* custom config setup */
3095 register_config_cli();
3098 if (ast_opt_console) {
3099 if (el_hist == NULL || el == NULL)
3100 ast_el_initialize();
3102 if (!ast_strlen_zero(filename))
3103 ast_el_read_history(filename);
3106 if (ast_tryconnect()) {