use tzafrir's patch to fix this problem properly... i made the previous set of change...
[asterisk-bristuff.git] / main / asterisk.c
blob17b3581f176a57778deffb8d49ac2ecdd4c2d30e
1 /*
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 */
21 /*!
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
28 * \arg \ref DevDoc
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
54 /*! \file
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
60 #include "asterisk.h"
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
64 #undef sched_setscheduler
65 #undef setpriority
66 #include <unistd.h>
67 #include <stdlib.h>
68 #include <sys/time.h>
69 #include <fcntl.h>
70 #include <stdio.h>
71 #include <signal.h>
72 #include <sched.h>
73 #include <sys/socket.h>
74 #include <sys/un.h>
75 #include <sys/wait.h>
76 #include <string.h>
77 #include <errno.h>
78 #include <ctype.h>
79 #include <sys/resource.h>
80 #include <grp.h>
81 #include <pwd.h>
82 #include <sys/stat.h>
84 #if defined(HAVE_ZAPTEL) || defined (HAVE_DAHDI)
85 #include <sys/ioctl.h>
86 #include "asterisk/dahdi_compat.h"
87 #endif
89 #ifdef linux
90 #include <sys/prctl.h>
91 #ifdef HAVE_CAP
92 #include <sys/capability.h>
93 #endif /* HAVE_CAP */
94 #endif /* linux */
95 #include <regex.h>
97 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
98 #include <netdb.h>
99 #if defined(SOLARIS)
100 int daemon(int, int); /* defined in libresolv of all places */
101 #endif
102 #endif
104 #include "asterisk/logger.h"
105 #include "asterisk/options.h"
106 #include "asterisk/cli.h"
107 #include "asterisk/channel.h"
108 #include "asterisk/ulaw.h"
109 #include "asterisk/alaw.h"
110 #include "asterisk/callerid.h"
111 #include "asterisk/image.h"
112 #include "asterisk/tdd.h"
113 #include "asterisk/term.h"
114 #include "asterisk/manager.h"
115 #include "asterisk/cdr.h"
116 #include "asterisk/pbx.h"
117 #include "asterisk/enum.h"
118 #include "asterisk/rtp.h"
119 #include "asterisk/http.h"
120 #include "asterisk/udptl.h"
121 #include "asterisk/app.h"
122 #include "asterisk/lock.h"
123 #include "asterisk/utils.h"
124 #include "asterisk/file.h"
125 #include "asterisk/io.h"
126 #include "asterisk/lock.h"
127 #include "editline/histedit.h"
128 #include "asterisk/config.h"
129 #include "asterisk/version.h"
130 #include "asterisk/linkedlists.h"
131 #include "asterisk/devicestate.h"
132 #include "asterisk/module.h"
134 #include "asterisk/doxyref.h" /* Doxygen documentation */
136 #include "../defaults.h"
138 #ifndef AF_LOCAL
139 #define AF_LOCAL AF_UNIX
140 #define PF_LOCAL PF_UNIX
141 #endif
143 #define AST_MAX_CONNECTS 128
144 #define NUM_MSGS 64
146 /*! \brief Welcome message when starting a CLI interface */
147 #define WELCOME_MESSAGE \
148 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008 Digium, Inc. and others.\n"); \
149 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
150 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
151 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
152 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
153 ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
154 ast_verbose("=========================================================================\n")
156 /*! \defgroup main_options Main Configuration Options
157 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
158 the operating system command line when starting Asterisk
159 Some of them can be changed in the CLI
161 /*! @{ */
163 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
165 int option_verbose; /*!< Verbosity level */
166 int option_debug; /*!< Debug level */
168 double option_maxload; /*!< Max load avg on system */
169 int option_maxcalls; /*!< Max number of active calls */
171 /*! @} */
173 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
174 char debug_filename[AST_FILENAME_MAX] = "";
175 char dahdi_chan_name[AST_CHANNEL_NAME] = "ZAP";
177 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
178 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
179 pid_t ast_mainpid;
180 struct console {
181 int fd; /*!< File descriptor */
182 int p[2]; /*!< Pipe */
183 pthread_t t; /*!< Thread of handler */
184 int mute; /*!< Is the console muted for logs */
187 struct ast_atexit {
188 void (*func)(void);
189 AST_LIST_ENTRY(ast_atexit) list;
192 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
194 time_t ast_startuptime;
195 time_t ast_lastreloadtime;
197 static History *el_hist;
198 static EditLine *el;
199 static char *remotehostname;
201 struct console consoles[AST_MAX_CONNECTS];
203 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
205 static int ast_el_add_history(char *);
206 static int ast_el_read_history(char *);
207 static int ast_el_write_history(char *);
209 char ast_config_AST_CONFIG_DIR[PATH_MAX];
210 char ast_config_AST_CONFIG_FILE[PATH_MAX];
211 char ast_config_AST_MODULE_DIR[PATH_MAX];
212 char ast_config_AST_SPOOL_DIR[PATH_MAX];
213 char ast_config_AST_MONITOR_DIR[PATH_MAX];
214 char ast_config_AST_VAR_DIR[PATH_MAX];
215 char ast_config_AST_DATA_DIR[PATH_MAX];
216 char ast_config_AST_LOG_DIR[PATH_MAX];
217 char ast_config_AST_AGI_DIR[PATH_MAX];
218 char ast_config_AST_DB[PATH_MAX];
219 char ast_config_AST_KEY_DIR[PATH_MAX];
220 char ast_config_AST_PID[PATH_MAX];
221 char ast_config_AST_SOCKET[PATH_MAX];
222 char ast_config_AST_RUN_DIR[PATH_MAX];
223 char ast_config_AST_RUN_USER[PATH_MAX];
224 char ast_config_AST_RUN_GROUP[PATH_MAX];
225 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
226 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
227 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
228 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
229 char ast_config_AST_SYSTEM_NAME[20] = "";
231 extern const char *ast_build_hostname;
232 extern const char *ast_build_kernel;
233 extern const char *ast_build_machine;
234 extern const char *ast_build_os;
235 extern const char *ast_build_date;
236 extern const char *ast_build_user;
238 static char *_argv[256];
239 static int shuttingdown;
240 static int restartnow;
241 static pthread_t consolethread = AST_PTHREADT_NULL;
243 static char randompool[256];
245 static int sig_alert_pipe[2] = { -1, -1 };
246 static struct {
247 unsigned int need_reload:1;
248 unsigned int need_quit:1;
249 } sig_flags;
251 #if !defined(LOW_MEMORY)
252 struct file_version {
253 AST_LIST_ENTRY(file_version) list;
254 const char *file;
255 char *version;
258 static AST_LIST_HEAD_STATIC(file_versions, file_version);
260 void ast_register_file_version(const char *file, const char *version)
262 struct file_version *new;
263 char *work;
264 size_t version_length;
266 work = ast_strdupa(version);
267 work = ast_strip(ast_strip_quoted(work, "$", "$"));
268 version_length = strlen(work) + 1;
270 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
271 return;
273 new->file = file;
274 new->version = (char *) new + sizeof(*new);
275 memcpy(new->version, work, version_length);
276 AST_LIST_LOCK(&file_versions);
277 AST_LIST_INSERT_HEAD(&file_versions, new, list);
278 AST_LIST_UNLOCK(&file_versions);
281 void ast_unregister_file_version(const char *file)
283 struct file_version *find;
285 AST_LIST_LOCK(&file_versions);
286 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
287 if (!strcasecmp(find->file, file)) {
288 AST_LIST_REMOVE_CURRENT(&file_versions, list);
289 break;
292 AST_LIST_TRAVERSE_SAFE_END;
293 AST_LIST_UNLOCK(&file_versions);
294 if (find)
295 free(find);
298 struct thread_list_t {
299 AST_LIST_ENTRY(thread_list_t) list;
300 char *name;
301 pthread_t id;
304 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
306 static char show_threads_help[] =
307 "Usage: core show threads\n"
308 " List threads currently active in the system.\n";
310 void ast_register_thread(char *name)
312 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
314 if (!new)
315 return;
316 new->id = pthread_self();
317 new->name = name; /* steal the allocated memory for the thread name */
318 AST_LIST_LOCK(&thread_list);
319 AST_LIST_INSERT_HEAD(&thread_list, new, list);
320 AST_LIST_UNLOCK(&thread_list);
323 void ast_unregister_thread(void *id)
325 struct thread_list_t *x;
327 AST_LIST_LOCK(&thread_list);
328 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
329 if ((void *) x->id == id) {
330 AST_LIST_REMOVE_CURRENT(&thread_list, list);
331 break;
334 AST_LIST_TRAVERSE_SAFE_END;
335 AST_LIST_UNLOCK(&thread_list);
336 if (x) {
337 free(x->name);
338 free(x);
342 static int handle_show_threads(int fd, int argc, char *argv[])
344 int count = 0;
345 struct thread_list_t *cur;
347 AST_LIST_LOCK(&thread_list);
348 AST_LIST_TRAVERSE(&thread_list, cur, list) {
349 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
350 count++;
352 AST_LIST_UNLOCK(&thread_list);
353 ast_cli(fd, "%d threads listed.\n", count);
354 return 0;
357 struct profile_entry {
358 const char *name;
359 uint64_t scale; /* if non-zero, values are scaled by this */
360 int64_t mark;
361 int64_t value;
362 int64_t events;
365 struct profile_data {
366 int entries;
367 int max_size;
368 struct profile_entry e[0];
371 static struct profile_data *prof_data;
373 /*! \brief allocates a counter with a given name and scale.
374 * \return Returns the identifier of the counter.
376 int ast_add_profile(const char *name, uint64_t scale)
378 int l = sizeof(struct profile_data);
379 int n = 10; /* default entries */
381 if (prof_data == NULL) {
382 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
383 if (prof_data == NULL)
384 return -1;
385 prof_data->entries = 0;
386 prof_data->max_size = n;
388 if (prof_data->entries >= prof_data->max_size) {
389 void *p;
390 n = prof_data->max_size + 20;
391 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
392 if (p == NULL)
393 return -1;
394 prof_data = p;
395 prof_data->max_size = n;
397 n = prof_data->entries++;
398 prof_data->e[n].name = ast_strdup(name);
399 prof_data->e[n].value = 0;
400 prof_data->e[n].events = 0;
401 prof_data->e[n].mark = 0;
402 prof_data->e[n].scale = scale;
403 return n;
406 int64_t ast_profile(int i, int64_t delta)
408 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
409 return 0;
410 if (prof_data->e[i].scale > 1)
411 delta /= prof_data->e[i].scale;
412 prof_data->e[i].value += delta;
413 prof_data->e[i].events++;
414 return prof_data->e[i].value;
417 /* The RDTSC instruction was introduced on the Pentium processor and is not
418 * implemented on certain clones, like the Cyrix 586. Hence, the previous
419 * expectation of __i386__ was in error. */
420 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
421 #if defined(__FreeBSD__)
422 #include <machine/cpufunc.h>
423 #elif defined(linux)
424 static __inline uint64_t
425 rdtsc(void)
427 uint64_t rv;
429 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
430 return (rv);
432 #endif
433 #else /* supply a dummy function on other platforms */
434 static __inline uint64_t
435 rdtsc(void)
437 return 0;
439 #endif
441 int64_t ast_mark(int i, int startstop)
443 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
444 return 0;
445 if (startstop == 1)
446 prof_data->e[i].mark = rdtsc();
447 else {
448 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
449 if (prof_data->e[i].scale > 1)
450 prof_data->e[i].mark /= prof_data->e[i].scale;
451 prof_data->e[i].value += prof_data->e[i].mark;
452 prof_data->e[i].events++;
454 return prof_data->e[i].mark;
457 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
459 int i, min, max;
460 char *search = NULL;
462 if (prof_data == NULL)
463 return 0;
465 min = 0;
466 max = prof_data->entries;
467 if (argc >= 3) { /* specific entries */
468 if (isdigit(argv[2][0])) {
469 min = atoi(argv[2]);
470 if (argc == 4 && strcmp(argv[3], "-"))
471 max = atoi(argv[3]);
472 } else
473 search = argv[2];
475 if (max > prof_data->entries)
476 max = prof_data->entries;
477 if (!strcmp(argv[0], "clear")) {
478 for (i= min; i < max; i++) {
479 if (!search || strstr(prof_data->e[i].name, search)) {
480 prof_data->e[i].value = 0;
481 prof_data->e[i].events = 0;
484 return 0;
486 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
487 prof_data->entries, prof_data->max_size);
488 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
489 "Value", "Average", "Name");
490 for (i = min; i < max; i++) {
491 struct profile_entry *e = &prof_data->e[i];
492 if (!search || strstr(prof_data->e[i].name, search))
493 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
495 (long)e->scale,
496 (long)e->events, (long long)e->value,
497 (long long)(e->events ? e->value / e->events : e->value),
498 e->name);
500 return 0;
503 static int handle_show_profile(int fd, int argc, char *argv[])
505 int i, min, max;
506 char *search = NULL;
508 if (prof_data == NULL)
509 return 0;
511 min = 0;
512 max = prof_data->entries;
513 if (argc > 3) { /* specific entries */
514 if (isdigit(argv[3][0])) {
515 min = atoi(argv[3]);
516 if (argc == 5 && strcmp(argv[4], "-"))
517 max = atoi(argv[4]);
518 } else
519 search = argv[3];
521 if (max > prof_data->entries)
522 max = prof_data->entries;
523 if (!strcmp(argv[1], "clear")) {
524 for (i= min; i < max; i++) {
525 if (!search || strstr(prof_data->e[i].name, search)) {
526 prof_data->e[i].value = 0;
527 prof_data->e[i].events = 0;
530 return 0;
532 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
533 prof_data->entries, prof_data->max_size);
534 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
535 "Value", "Average", "Name");
536 for (i = min; i < max; i++) {
537 struct profile_entry *e = &prof_data->e[i];
538 if (!search || strstr(prof_data->e[i].name, search))
539 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
541 (long)e->scale,
542 (long)e->events, (long long)e->value,
543 (long long)(e->events ? e->value / e->events : e->value),
544 e->name);
546 return 0;
549 static char show_version_files_help[] =
550 "Usage: core show file version [like <pattern>]\n"
551 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
552 " Optional regular expression pattern is used to filter the file list.\n";
554 /*! \brief CLI command to list module versions */
555 static int handle_show_version_files_deprecated(int fd, int argc, char *argv[])
557 #define FORMAT "%-25.25s %-40.40s\n"
558 struct file_version *iterator;
559 regex_t regexbuf;
560 int havepattern = 0;
561 int havename = 0;
562 int count_files = 0;
564 switch (argc) {
565 case 5:
566 if (!strcasecmp(argv[3], "like")) {
567 if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
568 return RESULT_SHOWUSAGE;
569 havepattern = 1;
570 } else
571 return RESULT_SHOWUSAGE;
572 break;
573 case 4:
574 havename = 1;
575 break;
576 case 3:
577 break;
578 default:
579 return RESULT_SHOWUSAGE;
582 ast_cli(fd, FORMAT, "File", "Revision");
583 ast_cli(fd, FORMAT, "----", "--------");
584 AST_LIST_LOCK(&file_versions);
585 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
586 if (havename && strcasecmp(iterator->file, argv[3]))
587 continue;
589 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
590 continue;
592 ast_cli(fd, FORMAT, iterator->file, iterator->version);
593 count_files++;
594 if (havename)
595 break;
597 AST_LIST_UNLOCK(&file_versions);
598 if (!havename) {
599 ast_cli(fd, "%d files listed.\n", count_files);
602 if (havepattern)
603 regfree(&regexbuf);
605 return RESULT_SUCCESS;
606 #undef FORMAT
609 static int handle_show_version_files(int fd, int argc, char *argv[])
611 #define FORMAT "%-25.25s %-40.40s\n"
612 struct file_version *iterator;
613 regex_t regexbuf;
614 int havepattern = 0;
615 int havename = 0;
616 int count_files = 0;
618 switch (argc) {
619 case 6:
620 if (!strcasecmp(argv[4], "like")) {
621 if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
622 return RESULT_SHOWUSAGE;
623 havepattern = 1;
624 } else
625 return RESULT_SHOWUSAGE;
626 break;
627 case 5:
628 havename = 1;
629 break;
630 case 4:
631 break;
632 default:
633 return RESULT_SHOWUSAGE;
636 ast_cli(fd, FORMAT, "File", "Revision");
637 ast_cli(fd, FORMAT, "----", "--------");
638 AST_LIST_LOCK(&file_versions);
639 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
640 if (havename && strcasecmp(iterator->file, argv[4]))
641 continue;
643 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
644 continue;
646 ast_cli(fd, FORMAT, iterator->file, iterator->version);
647 count_files++;
648 if (havename)
649 break;
651 AST_LIST_UNLOCK(&file_versions);
652 if (!havename) {
653 ast_cli(fd, "%d files listed.\n", count_files);
656 if (havepattern)
657 regfree(&regexbuf);
659 return RESULT_SUCCESS;
660 #undef FORMAT
663 static char *complete_show_version_files_deprecated(const char *line, const char *word, int pos, int state)
665 struct file_version *find;
666 int which = 0;
667 char *ret = NULL;
668 int matchlen = strlen(word);
670 if (pos != 3)
671 return NULL;
673 AST_LIST_LOCK(&file_versions);
674 AST_LIST_TRAVERSE(&file_versions, find, list) {
675 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
676 ret = ast_strdup(find->file);
677 break;
680 AST_LIST_UNLOCK(&file_versions);
682 return ret;
685 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
687 struct file_version *find;
688 int which = 0;
689 char *ret = NULL;
690 int matchlen = strlen(word);
692 if (pos != 4)
693 return NULL;
695 AST_LIST_LOCK(&file_versions);
696 AST_LIST_TRAVERSE(&file_versions, find, list) {
697 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
698 ret = ast_strdup(find->file);
699 break;
702 AST_LIST_UNLOCK(&file_versions);
704 return ret;
707 #endif /* ! LOW_MEMORY */
709 int ast_register_atexit(void (*func)(void))
711 struct ast_atexit *ae;
713 if (!(ae = ast_calloc(1, sizeof(*ae))))
714 return -1;
716 ae->func = func;
718 ast_unregister_atexit(func);
720 AST_LIST_LOCK(&atexits);
721 AST_LIST_INSERT_HEAD(&atexits, ae, list);
722 AST_LIST_UNLOCK(&atexits);
724 return 0;
727 void ast_unregister_atexit(void (*func)(void))
729 struct ast_atexit *ae = NULL;
731 AST_LIST_LOCK(&atexits);
732 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
733 if (ae->func == func) {
734 AST_LIST_REMOVE_CURRENT(&atexits, list);
735 break;
738 AST_LIST_TRAVERSE_SAFE_END
739 AST_LIST_UNLOCK(&atexits);
741 if (ae)
742 free(ae);
745 /* Sending commands from consoles back to the daemon requires a terminating NULL */
746 static int fdsend(int fd, const char *s)
748 return write(fd, s, strlen(s) + 1);
751 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
752 static int fdprint(int fd, const char *s)
754 return write(fd, s, strlen(s));
757 /*! \brief NULL handler so we can collect the child exit status */
758 static void null_sig_handler(int signal)
763 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
764 /*! \brief Keep track of how many threads are currently trying to wait*() on
765 * a child process */
766 static unsigned int safe_system_level = 0;
767 static void *safe_system_prev_handler;
769 void ast_replace_sigchld(void)
771 unsigned int level;
773 ast_mutex_lock(&safe_system_lock);
774 level = safe_system_level++;
776 /* only replace the handler if it has not already been done */
777 if (level == 0)
778 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
780 ast_mutex_unlock(&safe_system_lock);
783 void ast_unreplace_sigchld(void)
785 unsigned int level;
787 ast_mutex_lock(&safe_system_lock);
788 level = --safe_system_level;
790 /* only restore the handler if we are the last one */
791 if (level == 0)
792 signal(SIGCHLD, safe_system_prev_handler);
794 ast_mutex_unlock(&safe_system_lock);
797 int ast_safe_system(const char *s)
799 pid_t pid;
800 #ifdef HAVE_WORKING_FORK
801 int x;
802 #endif
803 int res;
804 struct rusage rusage;
805 int status;
807 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
808 ast_replace_sigchld();
810 #ifdef HAVE_WORKING_FORK
811 pid = fork();
812 #else
813 pid = vfork();
814 #endif
816 if (pid == 0) {
817 #ifdef HAVE_WORKING_FORK
818 if (ast_opt_high_priority)
819 ast_set_priority(0);
820 /* Close file descriptors and launch system command */
821 for (x = STDERR_FILENO + 1; x < 4096; x++)
822 close(x);
823 #endif
824 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
825 _exit(1);
826 } else if (pid > 0) {
827 for(;;) {
828 res = wait4(pid, &status, 0, &rusage);
829 if (res > -1) {
830 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
831 break;
832 } else if (errno != EINTR)
833 break;
835 } else {
836 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
837 res = -1;
840 ast_unreplace_sigchld();
841 #else
842 res = -1;
843 #endif
845 return res;
849 * \brief mute or unmute a console from logging
851 void ast_console_toggle_mute(int fd, int silent) {
852 int x;
853 for (x = 0;x < AST_MAX_CONNECTS; x++) {
854 if (fd == consoles[x].fd) {
855 if (consoles[x].mute) {
856 consoles[x].mute = 0;
857 if (!silent)
858 ast_cli(fd, "Console is not muted anymore.\n");
859 } else {
860 consoles[x].mute = 1;
861 if (!silent)
862 ast_cli(fd, "Console is muted.\n");
864 return;
867 ast_cli(fd, "Couldn't find remote console.\n");
871 * \brief log the string to all attached console clients
873 static void ast_network_puts_mutable(const char *string)
875 int x;
876 for (x = 0;x < AST_MAX_CONNECTS; x++) {
877 if (consoles[x].mute)
878 continue;
879 if (consoles[x].fd > -1)
880 fdprint(consoles[x].p[1], string);
885 * \brief log the string to the console, and all attached
886 * console clients
888 void ast_console_puts_mutable(const char *string)
890 fputs(string, stdout);
891 fflush(stdout);
892 ast_network_puts_mutable(string);
896 * \brief write the string to all attached console clients
898 static void ast_network_puts(const char *string)
900 int x;
901 for (x=0; x < AST_MAX_CONNECTS; x++) {
902 if (consoles[x].fd > -1)
903 fdprint(consoles[x].p[1], string);
908 * write the string to the console, and all attached
909 * console clients
911 void ast_console_puts(const char *string)
913 fputs(string, stdout);
914 fflush(stdout);
915 ast_network_puts(string);
918 static void network_verboser(const char *s)
920 ast_network_puts_mutable(s);
923 static pthread_t lthread;
925 static void *netconsole(void *vconsole)
927 struct console *con = vconsole;
928 char hostname[MAXHOSTNAMELEN] = "";
929 char tmp[512];
930 int res;
931 struct pollfd fds[2];
933 if (gethostname(hostname, sizeof(hostname)-1))
934 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
935 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
936 fdprint(con->fd, tmp);
937 for(;;) {
938 fds[0].fd = con->fd;
939 fds[0].events = POLLIN;
940 fds[0].revents = 0;
941 fds[1].fd = con->p[0];
942 fds[1].events = POLLIN;
943 fds[1].revents = 0;
945 res = poll(fds, 2, -1);
946 if (res < 0) {
947 if (errno != EINTR)
948 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
949 continue;
951 if (fds[0].revents) {
952 res = read(con->fd, tmp, sizeof(tmp));
953 if (res < 1) {
954 break;
956 tmp[res] = 0;
957 ast_cli_command_multiple(con->fd, res, tmp);
959 if (fds[1].revents) {
960 res = read(con->p[0], tmp, sizeof(tmp));
961 if (res < 1) {
962 ast_log(LOG_ERROR, "read returned %d\n", res);
963 break;
965 res = write(con->fd, tmp, res);
966 if (res < 1)
967 break;
970 if (option_verbose > 2)
971 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
972 close(con->fd);
973 close(con->p[0]);
974 close(con->p[1]);
975 con->fd = -1;
977 return NULL;
980 static void *listener(void *unused)
982 struct sockaddr_un sunaddr;
983 int s;
984 socklen_t len;
985 int x;
986 int flags;
987 struct pollfd fds[1];
988 pthread_attr_t attr;
989 pthread_attr_init(&attr);
990 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
991 for (;;) {
992 if (ast_socket < 0)
993 return NULL;
994 fds[0].fd = ast_socket;
995 fds[0].events = POLLIN;
996 s = poll(fds, 1, -1);
997 pthread_testcancel();
998 if (s < 0) {
999 if (errno != EINTR)
1000 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1001 continue;
1003 len = sizeof(sunaddr);
1004 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1005 if (s < 0) {
1006 if (errno != EINTR)
1007 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1008 } else {
1009 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1010 if (consoles[x].fd < 0) {
1011 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1012 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1013 consoles[x].fd = -1;
1014 fdprint(s, "Server failed to create pipe\n");
1015 close(s);
1016 break;
1018 flags = fcntl(consoles[x].p[1], F_GETFL);
1019 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1020 consoles[x].fd = s;
1021 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1022 if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) {
1023 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1024 close(consoles[x].p[0]);
1025 close(consoles[x].p[1]);
1026 consoles[x].fd = -1;
1027 fdprint(s, "Server failed to spawn thread\n");
1028 close(s);
1030 break;
1033 if (x >= AST_MAX_CONNECTS) {
1034 fdprint(s, "No more connections allowed\n");
1035 ast_log(LOG_WARNING, "No more connections allowed\n");
1036 close(s);
1037 } else if (consoles[x].fd > -1) {
1038 if (option_verbose > 2)
1039 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
1043 return NULL;
1046 static int ast_makesocket(void)
1048 struct sockaddr_un sunaddr;
1049 int res;
1050 int x;
1051 uid_t uid = -1;
1052 gid_t gid = -1;
1054 for (x = 0; x < AST_MAX_CONNECTS; x++)
1055 consoles[x].fd = -1;
1056 unlink(ast_config_AST_SOCKET);
1057 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1058 if (ast_socket < 0) {
1059 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1060 return -1;
1062 memset(&sunaddr, 0, sizeof(sunaddr));
1063 sunaddr.sun_family = AF_LOCAL;
1064 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1065 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1066 if (res) {
1067 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1068 close(ast_socket);
1069 ast_socket = -1;
1070 return -1;
1072 res = listen(ast_socket, 2);
1073 if (res < 0) {
1074 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1075 close(ast_socket);
1076 ast_socket = -1;
1077 return -1;
1079 ast_register_verbose(network_verboser);
1080 ast_pthread_create_background(&lthread, NULL, listener, NULL);
1082 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1083 struct passwd *pw;
1084 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
1085 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1086 } else {
1087 uid = pw->pw_uid;
1091 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1092 struct group *grp;
1093 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
1094 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1095 } else {
1096 gid = grp->gr_gid;
1100 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1101 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1103 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1104 int p1;
1105 mode_t p;
1106 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
1107 p = p1;
1108 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1109 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1112 return 0;
1115 static int ast_tryconnect(void)
1117 struct sockaddr_un sunaddr;
1118 int res;
1119 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1120 if (ast_consock < 0) {
1121 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1122 return 0;
1124 memset(&sunaddr, 0, sizeof(sunaddr));
1125 sunaddr.sun_family = AF_LOCAL;
1126 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1127 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1128 if (res) {
1129 close(ast_consock);
1130 ast_consock = -1;
1131 return 0;
1132 } else
1133 return 1;
1136 /*! \brief Urgent handler
1138 Called by soft_hangup to interrupt the poll, read, or other
1139 system call. We don't actually need to do anything though.
1140 Remember: Cannot EVER ast_log from within a signal handler
1142 static void urg_handler(int num)
1144 signal(num, urg_handler);
1145 return;
1148 static void hup_handler(int num)
1150 int a = 0;
1151 if (option_verbose > 1)
1152 printf("Received HUP signal -- Reloading configs\n");
1153 if (restartnow)
1154 execvp(_argv[0], _argv);
1155 sig_flags.need_reload = 1;
1156 if (sig_alert_pipe[1] != -1)
1157 write(sig_alert_pipe[1], &a, sizeof(a));
1158 signal(num, hup_handler);
1161 static void child_handler(int sig)
1163 /* Must not ever ast_log or ast_verbose within signal handler */
1164 int n, status;
1167 * Reap all dead children -- not just one
1169 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1171 if (n == 0 && option_debug)
1172 printf("Huh? Child handler, but nobody there?\n");
1173 signal(sig, child_handler);
1176 /*! \brief Set an X-term or screen title */
1177 static void set_title(char *text)
1179 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1180 fprintf(stdout, "\033]2;%s\007", text);
1183 static void set_icon(char *text)
1185 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1186 fprintf(stdout, "\033]1;%s\007", text);
1189 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1190 else. If your PBX has heavy activity on it, this is a good thing. */
1191 int ast_set_priority(int pri)
1193 struct sched_param sched;
1194 memset(&sched, 0, sizeof(sched));
1195 #ifdef __linux__
1196 if (pri) {
1197 sched.sched_priority = 10;
1198 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1199 ast_log(LOG_WARNING, "Unable to set high priority\n");
1200 return -1;
1201 } else
1202 if (option_verbose)
1203 ast_verbose("Set to realtime thread\n");
1204 } else {
1205 sched.sched_priority = 0;
1206 /* According to the manpage, these parameters can never fail. */
1207 sched_setscheduler(0, SCHED_OTHER, &sched);
1209 #else
1210 if (pri) {
1211 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1212 ast_log(LOG_WARNING, "Unable to set high priority\n");
1213 return -1;
1214 } else
1215 if (option_verbose)
1216 ast_verbose("Set to high priority\n");
1217 } else {
1218 /* According to the manpage, these parameters can never fail. */
1219 setpriority(PRIO_PROCESS, 0, 0);
1221 #endif
1222 return 0;
1225 static void ast_run_atexits(void)
1227 struct ast_atexit *ae;
1228 AST_LIST_LOCK(&atexits);
1229 AST_LIST_TRAVERSE(&atexits, ae, list) {
1230 if (ae->func)
1231 ae->func();
1233 AST_LIST_UNLOCK(&atexits);
1236 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1238 char filename[80] = "";
1239 time_t s,e;
1240 int x;
1241 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1242 ast_cdr_engine_term();
1243 if (safeshutdown) {
1244 shuttingdown = 1;
1245 if (!nice) {
1246 /* Begin shutdown routine, hanging up active channels */
1247 ast_begin_shutdown(1);
1248 if (option_verbose && ast_opt_console)
1249 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1250 time(&s);
1251 for (;;) {
1252 time(&e);
1253 /* Wait up to 15 seconds for all channels to go away */
1254 if ((e - s) > 15)
1255 break;
1256 if (!ast_active_channels())
1257 break;
1258 if (!shuttingdown)
1259 break;
1260 /* Sleep 1/10 of a second */
1261 usleep(100000);
1263 } else {
1264 if (nice < 2)
1265 ast_begin_shutdown(0);
1266 if (option_verbose && ast_opt_console)
1267 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1268 for (;;) {
1269 if (!ast_active_channels())
1270 break;
1271 if (!shuttingdown)
1272 break;
1273 sleep(1);
1277 if (!shuttingdown) {
1278 if (option_verbose && ast_opt_console)
1279 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1280 return;
1283 if (nice)
1284 ast_module_shutdown();
1286 if (ast_opt_console || ast_opt_remote) {
1287 if (getenv("HOME"))
1288 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1289 if (!ast_strlen_zero(filename))
1290 ast_el_write_history(filename);
1291 if (el != NULL)
1292 el_end(el);
1293 if (el_hist != NULL)
1294 history_end(el_hist);
1296 if (option_verbose)
1297 ast_verbose("Executing last minute cleanups\n");
1298 ast_run_atexits();
1299 /* Called on exit */
1300 if (option_verbose && ast_opt_console)
1301 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1302 if (option_debug)
1303 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1304 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1305 if (ast_socket > -1) {
1306 pthread_cancel(lthread);
1307 close(ast_socket);
1308 ast_socket = -1;
1309 unlink(ast_config_AST_SOCKET);
1311 if (ast_consock > -1)
1312 close(ast_consock);
1313 if (!ast_opt_remote)
1314 unlink(ast_config_AST_PID);
1315 printf(term_quit());
1316 if (restart) {
1317 if (option_verbose || ast_opt_console)
1318 ast_verbose("Preparing for Asterisk restart...\n");
1319 /* Mark all FD's for closing on exec */
1320 for (x=3; x < 32768; x++) {
1321 fcntl(x, F_SETFD, FD_CLOEXEC);
1323 if (option_verbose || ast_opt_console)
1324 ast_verbose("Asterisk is now restarting...\n");
1325 restartnow = 1;
1327 /* close logger */
1328 close_logger();
1330 /* If there is a consolethread running send it a SIGHUP
1331 so it can execvp, otherwise we can do it ourselves */
1332 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1333 pthread_kill(consolethread, SIGHUP);
1334 /* Give the signal handler some time to complete */
1335 sleep(2);
1336 } else
1337 execvp(_argv[0], _argv);
1339 } else {
1340 /* close logger */
1341 close_logger();
1343 exit(0);
1346 static void __quit_handler(int num)
1348 int a = 0;
1349 sig_flags.need_quit = 1;
1350 if (sig_alert_pipe[1] != -1)
1351 write(sig_alert_pipe[1], &a, sizeof(a));
1352 /* There is no need to restore the signal handler here, since the app
1353 * is going to exit */
1356 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1358 const char *c;
1360 /* Check for verboser preamble */
1361 if (*s == 127) {
1362 s++;
1365 if (!strncmp(s, cmp, strlen(cmp))) {
1366 c = s + strlen(cmp);
1367 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1368 return c;
1370 return NULL;
1373 static void console_verboser(const char *s)
1375 char tmp[80];
1376 const char *c = NULL;
1378 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1379 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1380 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1381 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1382 fputs(tmp, stdout);
1383 fputs(c, stdout);
1384 } else {
1385 if (*s == 127) {
1386 s++;
1388 fputs(s, stdout);
1391 fflush(stdout);
1393 /* Wake up a poll()ing console */
1394 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1395 pthread_kill(consolethread, SIGURG);
1398 static int ast_all_zeros(char *s)
1400 while (*s) {
1401 if (*s > 32)
1402 return 0;
1403 s++;
1405 return 1;
1408 static void consolehandler(char *s)
1410 printf(term_end());
1411 fflush(stdout);
1413 /* Called when readline data is available */
1414 if (!ast_all_zeros(s))
1415 ast_el_add_history(s);
1416 /* The real handler for bang */
1417 if (s[0] == '!') {
1418 if (s[1])
1419 ast_safe_system(s+1);
1420 else
1421 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1422 } else
1423 ast_cli_command(STDOUT_FILENO, s);
1426 static int remoteconsolehandler(char *s)
1428 int ret = 0;
1430 /* Called when readline data is available */
1431 if (!ast_all_zeros(s))
1432 ast_el_add_history(s);
1433 /* The real handler for bang */
1434 if (s[0] == '!') {
1435 if (s[1])
1436 ast_safe_system(s+1);
1437 else
1438 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1439 ret = 1;
1441 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1442 (s[4] == '\0' || isspace(s[4]))) {
1443 quit_handler(0, 0, 0, 0);
1444 ret = 1;
1447 return ret;
1450 static char abort_halt_help[] =
1451 "Usage: abort shutdown\n"
1452 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1453 " call operations.\n";
1455 static char shutdown_now_help[] =
1456 "Usage: stop now\n"
1457 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1459 static char shutdown_gracefully_help[] =
1460 "Usage: stop gracefully\n"
1461 " Causes Asterisk to not accept new calls, and exit when all\n"
1462 " active calls have terminated normally.\n";
1464 static char shutdown_when_convenient_help[] =
1465 "Usage: stop when convenient\n"
1466 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1468 static char restart_now_help[] =
1469 "Usage: restart now\n"
1470 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1471 " restart.\n";
1473 static char restart_gracefully_help[] =
1474 "Usage: restart gracefully\n"
1475 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1476 " restart when all active calls have ended.\n";
1478 static char restart_when_convenient_help[] =
1479 "Usage: restart when convenient\n"
1480 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1482 static char bang_help[] =
1483 "Usage: !<command>\n"
1484 " Executes a given shell command\n";
1486 static char show_warranty_help[] =
1487 "Usage: core show warranty\n"
1488 " Shows the warranty (if any) for this copy of Asterisk.\n";
1490 static char show_license_help[] =
1491 "Usage: core show license\n"
1492 " Shows the license(s) for this copy of Asterisk.\n";
1494 static char version_help[] =
1495 "Usage: core show version\n"
1496 " Shows Asterisk version information.\n";
1498 static int handle_version_deprecated(int fd, int argc, char *argv[])
1500 if (argc != 2)
1501 return RESULT_SHOWUSAGE;
1502 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1503 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1504 ast_build_machine, ast_build_os, ast_build_date);
1505 return RESULT_SUCCESS;
1508 static int handle_version(int fd, int argc, char *argv[])
1510 if (argc != 3)
1511 return RESULT_SHOWUSAGE;
1512 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1513 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1514 ast_build_machine, ast_build_os, ast_build_date);
1515 return RESULT_SUCCESS;
1518 #if 0
1519 static int handle_quit(int fd, int argc, char *argv[])
1521 if (argc != 1)
1522 return RESULT_SHOWUSAGE;
1523 quit_handler(0, 0, 1, 0);
1524 return RESULT_SUCCESS;
1526 #endif
1528 static int handle_shutdown_now(int fd, int argc, char *argv[])
1530 if (argc != 2)
1531 return RESULT_SHOWUSAGE;
1532 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1533 return RESULT_SUCCESS;
1536 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1538 if (argc != 2)
1539 return RESULT_SHOWUSAGE;
1540 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1541 return RESULT_SUCCESS;
1544 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1546 if (argc != 3)
1547 return RESULT_SHOWUSAGE;
1548 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1549 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1550 return RESULT_SUCCESS;
1553 static int handle_restart_now(int fd, int argc, char *argv[])
1555 if (argc != 2)
1556 return RESULT_SHOWUSAGE;
1557 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1558 return RESULT_SUCCESS;
1561 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1563 if (argc != 2)
1564 return RESULT_SHOWUSAGE;
1565 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1566 return RESULT_SUCCESS;
1569 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1571 if (argc != 3)
1572 return RESULT_SHOWUSAGE;
1573 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1574 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1575 return RESULT_SUCCESS;
1578 static int handle_abort_halt(int fd, int argc, char *argv[])
1580 if (argc != 2)
1581 return RESULT_SHOWUSAGE;
1582 ast_cancel_shutdown();
1583 shuttingdown = 0;
1584 return RESULT_SUCCESS;
1587 static int handle_bang(int fd, int argc, char *argv[])
1589 return RESULT_SUCCESS;
1591 static const char *warranty_lines[] = {
1592 "\n",
1593 " NO WARRANTY\n",
1594 "\n",
1595 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1596 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1597 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1598 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1599 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1600 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1601 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1602 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1603 "REPAIR OR CORRECTION.\n",
1604 "\n",
1605 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1606 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1607 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1608 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1609 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1610 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1611 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1612 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1613 "POSSIBILITY OF SUCH DAMAGES.\n",
1616 static int show_warranty(int fd, int argc, char *argv[])
1618 int x;
1620 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1621 ast_cli(fd, (char *) warranty_lines[x]);
1623 return RESULT_SUCCESS;
1626 static const char *license_lines[] = {
1627 "\n",
1628 "This program is free software; you can redistribute it and/or modify\n",
1629 "it under the terms of the GNU General Public License version 2 as\n",
1630 "published by the Free Software Foundation.\n",
1631 "\n",
1632 "This program also contains components licensed under other licenses.\n",
1633 "They include:\n",
1634 "\n",
1635 "This program is distributed in the hope that it will be useful,\n",
1636 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1637 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1638 "GNU General Public License for more details.\n",
1639 "\n",
1640 "You should have received a copy of the GNU General Public License\n",
1641 "along with this program; if not, write to the Free Software\n",
1642 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1645 static int show_license(int fd, int argc, char *argv[])
1647 int x;
1649 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1650 ast_cli(fd, (char *) license_lines[x]);
1652 return RESULT_SUCCESS;
1655 #define ASTERISK_PROMPT "*CLI> "
1657 #define ASTERISK_PROMPT2 "%s*CLI> "
1659 static struct ast_cli_entry cli_show_version_deprecated = {
1660 { "show", "version", NULL },
1661 handle_version_deprecated, "Display version info",
1662 version_help };
1664 #if !defined(LOW_MEMORY)
1665 static struct ast_cli_entry cli_show_version_files_deprecated = {
1666 { "show", "version", "files", NULL },
1667 handle_show_version_files_deprecated, NULL,
1668 NULL, complete_show_version_files_deprecated };
1670 static struct ast_cli_entry cli_show_profile_deprecated = {
1671 { "show", "profile", NULL },
1672 handle_show_profile_deprecated, NULL,
1673 NULL };
1675 static struct ast_cli_entry cli_clear_profile_deprecated = {
1676 { "clear", "profile", NULL },
1677 handle_show_profile_deprecated, NULL,
1678 NULL };
1679 #endif /* ! LOW_MEMORY */
1681 static struct ast_cli_entry cli_asterisk[] = {
1682 { { "abort", "halt", NULL },
1683 handle_abort_halt, "Cancel a running halt",
1684 abort_halt_help },
1686 { { "stop", "now", NULL },
1687 handle_shutdown_now, "Shut down Asterisk immediately",
1688 shutdown_now_help },
1690 { { "stop", "gracefully", NULL },
1691 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1692 shutdown_gracefully_help },
1694 { { "stop", "when", "convenient", NULL },
1695 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1696 shutdown_when_convenient_help },
1698 { { "restart", "now", NULL },
1699 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1701 { { "restart", "gracefully", NULL },
1702 handle_restart_gracefully, "Restart Asterisk gracefully",
1703 restart_gracefully_help },
1705 { { "restart", "when", "convenient", NULL },
1706 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1707 restart_when_convenient_help },
1709 { { "core", "show", "warranty", NULL },
1710 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1711 show_warranty_help },
1713 { { "core", "show", "license", NULL },
1714 show_license, "Show the license(s) for this copy of Asterisk",
1715 show_license_help },
1717 { { "core", "show", "version", NULL },
1718 handle_version, "Display version info",
1719 version_help, NULL, &cli_show_version_deprecated },
1721 { { "!", NULL },
1722 handle_bang, "Execute a shell command",
1723 bang_help },
1725 #if !defined(LOW_MEMORY)
1726 { { "core", "show", "file", "version", NULL },
1727 handle_show_version_files, "List versions of files used to build Asterisk",
1728 show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
1730 { { "core", "show", "threads", NULL },
1731 handle_show_threads, "Show running threads",
1732 show_threads_help },
1734 { { "core", "show", "profile", NULL },
1735 handle_show_profile, "Display profiling info",
1736 NULL, NULL, &cli_show_profile_deprecated },
1738 { { "core", "clear", "profile", NULL },
1739 handle_show_profile, "Clear profiling info",
1740 NULL, NULL, &cli_clear_profile_deprecated },
1741 #endif /* ! LOW_MEMORY */
1744 static int ast_el_read_char(EditLine *el, char *cp)
1746 int num_read = 0;
1747 int lastpos = 0;
1748 struct pollfd fds[2];
1749 int res;
1750 int max;
1751 #define EL_BUF_SIZE 512
1752 char buf[EL_BUF_SIZE];
1754 for (;;) {
1755 max = 1;
1756 fds[0].fd = ast_consock;
1757 fds[0].events = POLLIN;
1758 if (!ast_opt_exec) {
1759 fds[1].fd = STDIN_FILENO;
1760 fds[1].events = POLLIN;
1761 max++;
1763 res = poll(fds, max, -1);
1764 if (res < 0) {
1765 if (errno == EINTR)
1766 continue;
1767 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1768 break;
1771 if (!ast_opt_exec && fds[1].revents) {
1772 num_read = read(STDIN_FILENO, cp, 1);
1773 if (num_read < 1) {
1774 break;
1775 } else
1776 return (num_read);
1778 if (fds[0].revents) {
1779 char *tmp;
1780 res = read(ast_consock, buf, sizeof(buf) - 1);
1781 /* if the remote side disappears exit */
1782 if (res < 1) {
1783 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1784 if (!ast_opt_reconnect) {
1785 quit_handler(0, 0, 0, 0);
1786 } else {
1787 int tries;
1788 int reconnects_per_second = 20;
1789 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1790 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1791 if (ast_tryconnect()) {
1792 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1793 printf(term_quit());
1794 WELCOME_MESSAGE;
1795 if (!ast_opt_mute)
1796 fdsend(ast_consock, "logger mute silent");
1797 else
1798 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
1799 break;
1800 } else {
1801 usleep(1000000 / reconnects_per_second);
1804 if (tries >= 30 * reconnects_per_second) {
1805 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1806 quit_handler(0, 0, 0, 0);
1811 buf[res] = '\0';
1813 /* Strip preamble from asynchronous events, too */
1814 for (tmp = buf; *tmp; tmp++) {
1815 if (*tmp == 127) {
1816 memmove(tmp, tmp + 1, strlen(tmp));
1817 tmp--;
1821 /* Write over the CLI prompt */
1822 if (!ast_opt_exec && !lastpos)
1823 write(STDOUT_FILENO, "\r", 1);
1824 write(STDOUT_FILENO, buf, res);
1825 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
1826 *cp = CC_REFRESH;
1827 return(1);
1828 } else {
1829 lastpos = 1;
1834 *cp = '\0';
1835 return (0);
1838 static char *cli_prompt(EditLine *el)
1840 static char prompt[200];
1841 char *pfmt;
1842 int color_used = 0;
1843 char term_code[20];
1845 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1846 char *t = pfmt, *p = prompt;
1847 memset(prompt, 0, sizeof(prompt));
1848 while (*t != '\0' && *p < sizeof(prompt)) {
1849 if (*t == '%') {
1850 char hostname[MAXHOSTNAMELEN]="";
1851 int i;
1852 time_t ts;
1853 struct tm tm;
1854 #ifdef linux
1855 FILE *LOADAVG;
1856 #endif
1857 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1859 t++;
1860 switch (*t) {
1861 case 'C': /* color */
1862 t++;
1863 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1864 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1865 t += i - 1;
1866 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1867 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1868 t += i - 1;
1871 /* If the color has been reset correctly, then there's no need to reset it later */
1872 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1873 color_used = 0;
1874 } else {
1875 color_used = 1;
1877 break;
1878 case 'd': /* date */
1879 memset(&tm, 0, sizeof(tm));
1880 time(&ts);
1881 if (ast_localtime(&ts, &tm, NULL)) {
1882 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1884 break;
1885 case 'h': /* hostname */
1886 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1887 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1888 } else {
1889 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1891 break;
1892 case 'H': /* short hostname */
1893 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1894 for (i = 0; i < sizeof(hostname); i++) {
1895 if (hostname[i] == '.') {
1896 hostname[i] = '\0';
1897 break;
1900 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1901 } else {
1902 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1904 break;
1905 #ifdef linux
1906 case 'l': /* load avg */
1907 t++;
1908 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1909 float avg1, avg2, avg3;
1910 int actproc, totproc, npid, which;
1911 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1912 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1913 if (sscanf(t, "%d", &which) == 1) {
1914 switch (which) {
1915 case 1:
1916 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1917 break;
1918 case 2:
1919 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1920 break;
1921 case 3:
1922 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1923 break;
1924 case 4:
1925 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1926 break;
1927 case 5:
1928 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1929 break;
1933 break;
1934 #endif
1935 case 's': /* Asterisk system name (from asterisk.conf) */
1936 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1937 break;
1938 case 't': /* time */
1939 memset(&tm, 0, sizeof(tm));
1940 time(&ts);
1941 if (ast_localtime(&ts, &tm, NULL)) {
1942 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1944 break;
1945 case '#': /* process console or remote? */
1946 if (!ast_opt_remote) {
1947 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1948 } else {
1949 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1951 break;
1952 case '%': /* literal % */
1953 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1954 break;
1955 case '\0': /* % is last character - prevent bug */
1956 t--;
1957 break;
1959 while (*p != '\0') {
1960 p++;
1962 t++;
1963 } else {
1964 *p = *t;
1965 p++;
1966 t++;
1969 if (color_used) {
1970 /* Force colors back to normal at end */
1971 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1972 if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
1973 ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
1974 } else {
1975 /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
1976 strncat(p, term_code, sizeof(term_code));
1979 } else if (remotehostname)
1980 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1981 else
1982 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1984 return(prompt);
1987 static char **ast_el_strtoarr(char *buf)
1989 char **match_list = NULL, *retstr;
1990 size_t match_list_len;
1991 int matches = 0;
1993 match_list_len = 1;
1994 while ( (retstr = strsep(&buf, " ")) != NULL) {
1996 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1997 break;
1998 if (matches + 1 >= match_list_len) {
1999 match_list_len <<= 1;
2000 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2001 /* TODO: Handle memory allocation failure */
2005 match_list[matches++] = strdup(retstr);
2008 if (!match_list)
2009 return (char **) NULL;
2011 if (matches >= match_list_len) {
2012 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2013 /* TODO: Handle memory allocation failure */
2017 match_list[matches] = (char *) NULL;
2019 return match_list;
2022 static int ast_el_sort_compare(const void *i1, const void *i2)
2024 char *s1, *s2;
2026 s1 = ((char **)i1)[0];
2027 s2 = ((char **)i2)[0];
2029 return strcasecmp(s1, s2);
2032 static int ast_cli_display_match_list(char **matches, int len, int max)
2034 int i, idx, limit, count;
2035 int screenwidth = 0;
2036 int numoutput = 0, numoutputline = 0;
2038 screenwidth = ast_get_termcols(STDOUT_FILENO);
2040 /* find out how many entries can be put on one line, with two spaces between strings */
2041 limit = screenwidth / (max + 2);
2042 if (limit == 0)
2043 limit = 1;
2045 /* how many lines of output */
2046 count = len / limit;
2047 if (count * limit < len)
2048 count++;
2050 idx = 1;
2052 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2054 for (; count > 0; count--) {
2055 numoutputline = 0;
2056 for (i=0; i < limit && matches[idx]; i++, idx++) {
2058 /* Don't print dupes */
2059 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2060 i--;
2061 free(matches[idx]);
2062 matches[idx] = NULL;
2063 continue;
2066 numoutput++;
2067 numoutputline++;
2068 fprintf(stdout, "%-*s ", max, matches[idx]);
2069 free(matches[idx]);
2070 matches[idx] = NULL;
2072 if (numoutputline > 0)
2073 fprintf(stdout, "\n");
2076 return numoutput;
2080 static char *cli_complete(EditLine *el, int ch)
2082 int len = 0;
2083 char *ptr;
2084 int nummatches = 0;
2085 char **matches;
2086 int retval = CC_ERROR;
2087 char buf[2048];
2088 int res;
2090 LineInfo *lf = (LineInfo *)el_line(el);
2092 *(char *)lf->cursor = '\0';
2093 ptr = (char *)lf->cursor;
2094 if (ptr) {
2095 while (ptr > lf->buffer) {
2096 if (isspace(*ptr)) {
2097 ptr++;
2098 break;
2100 ptr--;
2104 len = lf->cursor - ptr;
2106 if (ast_opt_remote) {
2107 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2108 fdsend(ast_consock, buf);
2109 res = read(ast_consock, buf, sizeof(buf));
2110 buf[res] = '\0';
2111 nummatches = atoi(buf);
2113 if (nummatches > 0) {
2114 char *mbuf;
2115 int mlen = 0, maxmbuf = 2048;
2116 /* Start with a 2048 byte buffer */
2117 if (!(mbuf = ast_malloc(maxmbuf)))
2118 return (char *)(CC_ERROR);
2119 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2120 fdsend(ast_consock, buf);
2121 res = 0;
2122 mbuf[0] = '\0';
2123 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2124 if (mlen + 1024 > maxmbuf) {
2125 /* Every step increment buffer 1024 bytes */
2126 maxmbuf += 1024;
2127 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2128 return (char *)(CC_ERROR);
2130 /* Only read 1024 bytes at a time */
2131 res = read(ast_consock, mbuf + mlen, 1024);
2132 if (res > 0)
2133 mlen += res;
2135 mbuf[mlen] = '\0';
2137 matches = ast_el_strtoarr(mbuf);
2138 free(mbuf);
2139 } else
2140 matches = (char **) NULL;
2141 } else {
2142 char **p, *oldbuf=NULL;
2143 nummatches = 0;
2144 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2145 for (p = matches; p && *p; p++) {
2146 if (!oldbuf || strcmp(*p,oldbuf))
2147 nummatches++;
2148 oldbuf = *p;
2152 if (matches) {
2153 int i;
2154 int matches_num, maxlen, match_len;
2156 if (matches[0][0] != '\0') {
2157 el_deletestr(el, (int) len);
2158 el_insertstr(el, matches[0]);
2159 retval = CC_REFRESH;
2162 if (nummatches == 1) {
2163 /* Found an exact match */
2164 el_insertstr(el, " ");
2165 retval = CC_REFRESH;
2166 } else {
2167 /* Must be more than one match */
2168 for (i=1, maxlen=0; matches[i]; i++) {
2169 match_len = strlen(matches[i]);
2170 if (match_len > maxlen)
2171 maxlen = match_len;
2173 matches_num = i - 1;
2174 if (matches_num >1) {
2175 fprintf(stdout, "\n");
2176 ast_cli_display_match_list(matches, nummatches, maxlen);
2177 retval = CC_REDISPLAY;
2178 } else {
2179 el_insertstr(el," ");
2180 retval = CC_REFRESH;
2183 for (i = 0; matches[i]; i++)
2184 free(matches[i]);
2185 free(matches);
2188 return (char *)(long)retval;
2191 static int ast_el_initialize(void)
2193 HistEvent ev;
2194 char *editor = getenv("AST_EDITOR");
2196 if (el != NULL)
2197 el_end(el);
2198 if (el_hist != NULL)
2199 history_end(el_hist);
2201 el = el_init("asterisk", stdin, stdout, stderr);
2202 el_set(el, EL_PROMPT, cli_prompt);
2204 el_set(el, EL_EDITMODE, 1);
2205 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2206 el_hist = history_init();
2207 if (!el || !el_hist)
2208 return -1;
2210 /* setup history with 100 entries */
2211 history(el_hist, &ev, H_SETSIZE, 100);
2213 el_set(el, EL_HIST, history, el_hist);
2215 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2216 /* Bind <tab> to command completion */
2217 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2218 /* Bind ? to command completion */
2219 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2220 /* Bind ^D to redisplay */
2221 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2223 return 0;
2226 static int ast_el_add_history(char *buf)
2228 HistEvent ev;
2230 if (el_hist == NULL || el == NULL)
2231 ast_el_initialize();
2232 if (strlen(buf) > 256)
2233 return 0;
2234 return (history(el_hist, &ev, H_ENTER, buf));
2237 static int ast_el_write_history(char *filename)
2239 HistEvent ev;
2241 if (el_hist == NULL || el == NULL)
2242 ast_el_initialize();
2244 return (history(el_hist, &ev, H_SAVE, filename));
2247 static int ast_el_read_history(char *filename)
2249 char buf[256];
2250 FILE *f;
2251 int ret = -1;
2253 if (el_hist == NULL || el == NULL)
2254 ast_el_initialize();
2256 if ((f = fopen(filename, "r")) == NULL)
2257 return ret;
2259 while (!feof(f)) {
2260 fgets(buf, sizeof(buf), f);
2261 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2262 continue;
2263 if (ast_all_zeros(buf))
2264 continue;
2265 if ((ret = ast_el_add_history(buf)) == -1)
2266 break;
2268 fclose(f);
2270 return ret;
2273 static void ast_remotecontrol(char * data)
2275 char buf[80];
2276 int res;
2277 char filename[80] = "";
2278 char *hostname;
2279 char *cpid;
2280 char *version;
2281 int pid;
2282 char tmp[80];
2283 char *stringp = NULL;
2285 char *ebuf;
2286 int num = 0;
2288 read(ast_consock, buf, sizeof(buf));
2289 if (data)
2290 write(ast_consock, data, strlen(data) + 1);
2291 stringp = buf;
2292 hostname = strsep(&stringp, "/");
2293 cpid = strsep(&stringp, "/");
2294 version = strsep(&stringp, "\n");
2295 if (!version)
2296 version = "<Version Unknown>";
2297 stringp = hostname;
2298 strsep(&stringp, ".");
2299 if (cpid)
2300 pid = atoi(cpid);
2301 else
2302 pid = -1;
2303 if (!data) {
2304 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2305 fdsend(ast_consock, tmp);
2306 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2307 fdsend(ast_consock, tmp);
2308 if (!ast_opt_mute)
2309 fdsend(ast_consock, "logger mute silent");
2310 else
2311 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2313 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2314 remotehostname = hostname;
2315 if (getenv("HOME"))
2316 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2317 if (el_hist == NULL || el == NULL)
2318 ast_el_initialize();
2320 el_set(el, EL_GETCFN, ast_el_read_char);
2322 if (!ast_strlen_zero(filename))
2323 ast_el_read_history(filename);
2325 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2326 struct pollfd fds;
2327 fds.fd = ast_consock;
2328 fds.events = POLLIN;
2329 fds.revents = 0;
2330 while (poll(&fds, 1, 500) > 0) {
2331 char buf[512] = "", *curline = buf, *nextline;
2332 int not_written = 1;
2334 if (read(ast_consock, buf, sizeof(buf) - 1) <= 0) {
2335 break;
2338 do {
2339 if ((nextline = strchr(curline, '\n'))) {
2340 nextline++;
2341 } else {
2342 nextline = strchr(curline, '\0');
2345 /* Skip verbose lines */
2346 if (*curline != 127) {
2347 not_written = 0;
2348 write(STDOUT_FILENO, curline, nextline - curline);
2350 curline = nextline;
2351 } while (!ast_strlen_zero(curline));
2353 /* No non-verbose output in 500ms */
2354 if (not_written) {
2355 break;
2358 return;
2360 for (;;) {
2361 ebuf = (char *)el_gets(el, &num);
2363 if (!ebuf && write(1, "", 1) < 0)
2364 break;
2366 if (!ast_strlen_zero(ebuf)) {
2367 if (ebuf[strlen(ebuf)-1] == '\n')
2368 ebuf[strlen(ebuf)-1] = '\0';
2369 if (!remoteconsolehandler(ebuf)) {
2370 /* Strip preamble from output */
2371 char *tmp;
2372 for (tmp = ebuf; *tmp; tmp++) {
2373 if (*tmp == 127) {
2374 memmove(tmp, tmp + 1, strlen(tmp));
2375 tmp--;
2378 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2379 if (res < 1) {
2380 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2381 break;
2386 printf("\nDisconnected from Asterisk server\n");
2389 static int show_version(void)
2391 printf("Asterisk " ASTERISK_VERSION "\n");
2392 return 0;
2395 static int show_cli_help(void) {
2396 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008, Digium, Inc. and others.\n");
2397 printf("Usage: asterisk [OPTIONS]\n");
2398 printf("Valid Options:\n");
2399 printf(" -V Display version number and exit\n");
2400 printf(" -C <configfile> Use an alternate configuration file\n");
2401 printf(" -G <group> Run as a group other than the caller\n");
2402 printf(" -U <user> Run as a user other than the caller\n");
2403 printf(" -c Provide console CLI\n");
2404 printf(" -d Enable extra debugging\n");
2405 #if HAVE_WORKING_FORK
2406 printf(" -f Do not fork\n");
2407 printf(" -F Always fork\n");
2408 #endif
2409 printf(" -g Dump core in case of a crash\n");
2410 printf(" -h This help screen\n");
2411 printf(" -i Initialize crypto keys at startup\n");
2412 printf(" -I Enable internal timing if Zaptel timer is available\n");
2413 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2414 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2415 printf(" -m Mute debugging and console output on the console\n");
2416 printf(" -n Disable console colorization\n");
2417 printf(" -p Run as pseudo-realtime thread\n");
2418 printf(" -q Quiet mode (suppress output)\n");
2419 printf(" -r Connect to Asterisk on this machine\n");
2420 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2421 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2422 printf(" belong after they are done\n");
2423 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2424 printf(" of output to the CLI\n");
2425 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2426 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2427 printf("\n");
2428 return 0;
2431 static void ast_readconfig(void)
2433 struct ast_config *cfg;
2434 struct ast_variable *v;
2435 char *config = AST_CONFIG_FILE;
2437 if (ast_opt_override_config) {
2438 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2439 if (!cfg)
2440 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2441 } else {
2442 cfg = ast_config_load(config);
2445 /* init with buildtime config */
2446 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2447 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2448 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2449 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2450 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2451 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2452 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2453 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2454 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2455 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2456 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2457 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2458 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2460 /* no asterisk.conf? no problem, use buildtime config! */
2461 if (!cfg) {
2462 return;
2465 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2466 if (!strcasecmp(v->name, "astctlpermissions")) {
2467 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2468 } else if (!strcasecmp(v->name, "astctlowner")) {
2469 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2470 } else if (!strcasecmp(v->name, "astctlgroup")) {
2471 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2472 } else if (!strcasecmp(v->name, "astctl")) {
2473 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2477 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2478 if (!strcasecmp(v->name, "astetcdir")) {
2479 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2480 } else if (!strcasecmp(v->name, "astspooldir")) {
2481 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2482 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2483 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2484 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2485 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2486 } else if (!strcasecmp(v->name, "astdatadir")) {
2487 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2488 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2489 } else if (!strcasecmp(v->name, "astlogdir")) {
2490 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2491 } else if (!strcasecmp(v->name, "astagidir")) {
2492 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2493 } else if (!strcasecmp(v->name, "astrundir")) {
2494 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2495 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2496 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2497 } else if (!strcasecmp(v->name, "astmoddir")) {
2498 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2502 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2503 /* verbose level (-v at startup) */
2504 if (!strcasecmp(v->name, "verbose")) {
2505 option_verbose = atoi(v->value);
2506 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2507 } else if (!strcasecmp(v->name, "timestamp")) {
2508 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2509 /* whether or not to support #exec in config files */
2510 } else if (!strcasecmp(v->name, "execincludes")) {
2511 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2512 /* debug level (-d at startup) */
2513 } else if (!strcasecmp(v->name, "debug")) {
2514 option_debug = 0;
2515 if (sscanf(v->value, "%d", &option_debug) != 1) {
2516 option_debug = ast_true(v->value);
2518 #if HAVE_WORKING_FORK
2519 /* Disable forking (-f at startup) */
2520 } else if (!strcasecmp(v->name, "nofork")) {
2521 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2522 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2523 } else if (!strcasecmp(v->name, "alwaysfork")) {
2524 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2525 #endif
2526 /* Run quietly (-q at startup ) */
2527 } else if (!strcasecmp(v->name, "quiet")) {
2528 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2529 /* Run as console (-c at startup, implies nofork) */
2530 } else if (!strcasecmp(v->name, "console")) {
2531 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2532 /* Run with high priority if the O/S permits (-p at startup) */
2533 } else if (!strcasecmp(v->name, "highpriority")) {
2534 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2535 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2536 } else if (!strcasecmp(v->name, "initcrypto")) {
2537 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2538 /* Disable ANSI colors for console (-c at startup) */
2539 } else if (!strcasecmp(v->name, "nocolor")) {
2540 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2541 /* Disable some usage warnings for picky people :p */
2542 } else if (!strcasecmp(v->name, "dontwarn")) {
2543 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2544 /* Dump core in case of crash (-g) */
2545 } else if (!strcasecmp(v->name, "dumpcore")) {
2546 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2547 /* Cache recorded sound files to another directory during recording */
2548 } else if (!strcasecmp(v->name, "cache_record_files")) {
2549 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2550 /* Specify cache directory */
2551 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2552 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2553 /* Build transcode paths via SLINEAR, instead of directly */
2554 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2555 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2556 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2557 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2558 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2559 /* Enable internal timing */
2560 } else if (!strcasecmp(v->name, "internal_timing")) {
2561 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2562 } else if (!strcasecmp(v->name, "maxcalls")) {
2563 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2564 option_maxcalls = 0;
2566 } else if (!strcasecmp(v->name, "maxload")) {
2567 double test[1];
2569 if (getloadavg(test, 1) == -1) {
2570 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2571 option_maxload = 0.0;
2572 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2573 option_maxload = 0.0;
2575 /* What user to run as */
2576 } else if (!strcasecmp(v->name, "runuser")) {
2577 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2578 /* What group to run as */
2579 } else if (!strcasecmp(v->name, "rungroup")) {
2580 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2581 } else if (!strcasecmp(v->name, "systemname")) {
2582 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2583 } else if (!strcasecmp(v->name, "languageprefix")) {
2584 ast_language_is_prefix = ast_true(v->value);
2585 } else if (!strcasecmp(v->name, "dahdichanname")) {
2586 if (!strcasecmp(v->value, "yes")) {
2587 ast_copy_string(dahdi_chan_name, "DAHDI", sizeof(dahdi_chan_name));
2591 ast_config_destroy(cfg);
2594 static void *monitor_sig_flags(void *unused)
2596 for (;;) {
2597 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2598 int a;
2599 poll(&p, 1, -1);
2600 if (sig_flags.need_reload) {
2601 sig_flags.need_reload = 0;
2602 ast_module_reload(NULL);
2604 if (sig_flags.need_quit) {
2605 sig_flags.need_quit = 0;
2606 quit_handler(0, 0, 1, 0);
2608 read(sig_alert_pipe[0], &a, sizeof(a));
2611 return NULL;
2614 int main(int argc, char *argv[])
2616 int c;
2617 char filename[80] = "";
2618 char hostname[MAXHOSTNAMELEN] = "";
2619 char tmp[80];
2620 char * xarg = NULL;
2621 int x;
2622 FILE *f;
2623 sigset_t sigs;
2624 int num;
2625 int isroot = 1;
2626 char *buf;
2627 char *runuser = NULL, *rungroup = NULL;
2629 /* Remember original args for restart */
2630 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2631 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2632 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2634 for (x=0; x<argc; x++)
2635 _argv[x] = argv[x];
2636 _argv[x] = NULL;
2638 if (geteuid() != 0)
2639 isroot = 0;
2641 /* if the progname is rasterisk consider it a remote console */
2642 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2643 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2645 if (gethostname(hostname, sizeof(hostname)-1))
2646 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2647 ast_mainpid = getpid();
2648 ast_ulaw_init();
2649 ast_alaw_init();
2650 callerid_init();
2651 ast_builtins_init();
2652 ast_utils_init();
2653 tdd_init();
2655 if (getenv("HOME"))
2656 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2657 /* Check for options */
2658 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2659 switch (c) {
2660 #if HAVE_WORKING_FORK
2661 case 'F':
2662 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2663 break;
2664 case 'f':
2665 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2666 break;
2667 #endif
2668 case 'd':
2669 option_debug++;
2670 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2671 break;
2672 case 'c':
2673 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2674 break;
2675 case 'n':
2676 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2677 break;
2678 case 'r':
2679 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2680 break;
2681 case 'R':
2682 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2683 break;
2684 case 'p':
2685 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2686 break;
2687 case 'v':
2688 option_verbose++;
2689 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2690 break;
2691 case 'm':
2692 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2693 break;
2694 case 'M':
2695 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2696 option_maxcalls = 0;
2697 break;
2698 case 'L':
2699 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2700 option_maxload = 0.0;
2701 break;
2702 case 'q':
2703 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2704 break;
2705 case 't':
2706 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2707 break;
2708 case 'T':
2709 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2710 break;
2711 case 'x':
2712 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2713 xarg = ast_strdupa(optarg);
2714 break;
2715 case 'C':
2716 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2717 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2718 break;
2719 case 'I':
2720 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2721 break;
2722 case 'i':
2723 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2724 break;
2725 case 'g':
2726 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2727 break;
2728 case 'h':
2729 show_cli_help();
2730 exit(0);
2731 case 'V':
2732 show_version();
2733 exit(0);
2734 case 'U':
2735 runuser = ast_strdupa(optarg);
2736 break;
2737 case 'G':
2738 rungroup = ast_strdupa(optarg);
2739 break;
2740 case '?':
2741 exit(1);
2745 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2746 ast_register_verbose(console_verboser);
2747 WELCOME_MESSAGE;
2750 if (ast_opt_console && !option_verbose)
2751 ast_verbose("[ Booting...\n");
2753 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2754 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2755 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2758 /* For remote connections, change the name of the remote connection.
2759 * We do this for the benefit of init scripts (which need to know if/when
2760 * the main asterisk process has died yet). */
2761 if (ast_opt_remote) {
2762 strcpy(argv[0], "rasterisk");
2763 for (x = 1; x < argc; x++) {
2764 argv[x] = argv[0] + 10;
2768 if (ast_opt_console && !option_verbose)
2769 ast_verbose("[ Reading Master Configuration ]\n");
2770 ast_readconfig();
2772 if (ast_opt_dump_core) {
2773 struct rlimit l;
2774 memset(&l, 0, sizeof(l));
2775 l.rlim_cur = RLIM_INFINITY;
2776 l.rlim_max = RLIM_INFINITY;
2777 if (setrlimit(RLIMIT_CORE, &l)) {
2778 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2782 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2783 rungroup = ast_config_AST_RUN_GROUP;
2784 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2785 runuser = ast_config_AST_RUN_USER;
2787 #ifndef __CYGWIN__
2789 if (isroot)
2790 ast_set_priority(ast_opt_high_priority);
2792 if (isroot && rungroup) {
2793 struct group *gr;
2794 gr = getgrnam(rungroup);
2795 if (!gr) {
2796 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2797 exit(1);
2799 if (setgid(gr->gr_gid)) {
2800 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2801 exit(1);
2803 if (setgroups(0, NULL)) {
2804 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2805 exit(1);
2807 if (option_verbose)
2808 ast_verbose("Running as group '%s'\n", rungroup);
2811 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
2812 #ifdef HAVE_CAP
2813 int has_cap = 1;
2814 #endif /* HAVE_CAP */
2815 struct passwd *pw;
2816 pw = getpwnam(runuser);
2817 if (!pw) {
2818 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2819 exit(1);
2821 #ifdef HAVE_CAP
2822 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
2823 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
2824 has_cap = 0;
2826 #endif /* HAVE_CAP */
2827 if (!isroot && pw->pw_uid != geteuid()) {
2828 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
2829 exit(1);
2831 if (!rungroup) {
2832 if (setgid(pw->pw_gid)) {
2833 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2834 exit(1);
2836 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
2837 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2838 exit(1);
2841 if (setuid(pw->pw_uid)) {
2842 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2843 exit(1);
2845 if (option_verbose)
2846 ast_verbose("Running as user '%s'\n", runuser);
2847 #ifdef HAVE_CAP
2848 if (has_cap) {
2849 cap_t cap;
2851 cap = cap_from_text("cap_net_admin=ep");
2853 if (cap_set_proc(cap))
2854 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
2856 if (cap_free(cap))
2857 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
2859 #endif /* HAVE_CAP */
2862 #endif /* __CYGWIN__ */
2864 #ifdef linux
2865 if (geteuid() && ast_opt_dump_core) {
2866 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2867 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2870 #endif
2872 ast_term_init();
2873 printf(term_end());
2874 fflush(stdout);
2876 if (ast_opt_console && !option_verbose)
2877 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2878 /* custom config setup */
2879 register_config_cli();
2880 read_config_maps();
2882 if (ast_opt_console) {
2883 if (el_hist == NULL || el == NULL)
2884 ast_el_initialize();
2886 if (!ast_strlen_zero(filename))
2887 ast_el_read_history(filename);
2890 if (ast_tryconnect()) {
2891 /* One is already running */
2892 if (ast_opt_remote) {
2893 if (ast_opt_exec) {
2894 ast_remotecontrol(xarg);
2895 quit_handler(0, 0, 0, 0);
2896 exit(0);
2898 printf(term_quit());
2899 ast_remotecontrol(NULL);
2900 quit_handler(0, 0, 0, 0);
2901 exit(0);
2902 } else {
2903 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2904 printf(term_quit());
2905 exit(1);
2907 } else if (ast_opt_remote || ast_opt_exec) {
2908 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2909 printf(term_quit());
2910 exit(1);
2912 /* Blindly write pid file since we couldn't connect */
2913 unlink(ast_config_AST_PID);
2914 f = fopen(ast_config_AST_PID, "w");
2915 if (f) {
2916 fprintf(f, "%ld\n", (long)getpid());
2917 fclose(f);
2918 } else
2919 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2921 #if HAVE_WORKING_FORK
2922 if (ast_opt_always_fork || !ast_opt_no_fork) {
2923 #ifndef HAVE_SBIN_LAUNCHD
2924 daemon(1, 0);
2925 ast_mainpid = getpid();
2926 /* Blindly re-write pid file since we are forking */
2927 unlink(ast_config_AST_PID);
2928 f = fopen(ast_config_AST_PID, "w");
2929 if (f) {
2930 fprintf(f, "%ld\n", (long)ast_mainpid);
2931 fclose(f);
2932 } else
2933 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2934 #else
2935 ast_log(LOG_WARNING, "Mac OS X detected. Use '/sbin/launchd -d' to launch with the nofork option.\n");
2936 #endif
2938 #endif
2940 /* Test recursive mutex locking. */
2941 if (test_for_thread_safety())
2942 ast_verbose("Warning! Asterisk is not thread safe.\n");
2944 ast_makesocket();
2945 sigemptyset(&sigs);
2946 sigaddset(&sigs, SIGHUP);
2947 sigaddset(&sigs, SIGTERM);
2948 sigaddset(&sigs, SIGINT);
2949 sigaddset(&sigs, SIGPIPE);
2950 sigaddset(&sigs, SIGWINCH);
2951 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2952 signal(SIGURG, urg_handler);
2953 signal(SIGINT, __quit_handler);
2954 signal(SIGTERM, __quit_handler);
2955 signal(SIGHUP, hup_handler);
2956 signal(SIGCHLD, child_handler);
2957 signal(SIGPIPE, SIG_IGN);
2959 /* ensure that the random number generators are seeded with a different value every time
2960 Asterisk is started
2962 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2963 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2965 if (init_logger()) {
2966 printf(term_quit());
2967 exit(1);
2969 #ifdef HAVE_ZAPTEL
2971 int fd;
2972 int x = 160;
2973 fd = open("/dev/zap/timer", O_RDWR);
2974 if (fd >= 0) {
2975 if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
2976 ast_log(LOG_ERROR, "You have Zaptel built and drivers loaded, but the Zaptel timer test failed to set ZT_TIMERCONFIG to %d.\n", x);
2977 exit(1);
2979 if ((x = ast_wait_for_input(fd, 300)) < 0) {
2980 ast_log(LOG_ERROR, "You have Zaptel built and drivers loaded, but the Zaptel timer could not be polled during the Zaptel timer test.\n");
2981 exit(1);
2983 if (!x) {
2984 const char zaptel_timer_error[] = {
2985 "Asterisk has detected a problem with your Zaptel configuration and will shutdown for your protection. You have options:"
2986 "\n\t1. You only have to compile Zaptel support into Asterisk if you need it. One option is to recompile without Zaptel support."
2987 "\n\t2. You only have to load Zaptel drivers if you want to take advantage of Zaptel services. One option is to unload zaptel modules if you don't need them."
2988 "\n\t3. If you need Zaptel services, you must correctly configure Zaptel."
2990 ast_log(LOG_ERROR, "%s\n", zaptel_timer_error);
2991 exit(1);
2993 close(fd);
2996 #elif defined(HAVE_DAHDI)
2998 int fd;
2999 int x = 160;
3000 fd = open("/dev/dahdi/timer", O_RDWR);
3001 if (fd >= 0) {
3002 if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
3003 ast_log(LOG_ERROR, "You have DAHDI built and drivers loaded, but the DAHDI timer test failed to set DAHDI_TIMERCONFIG to %d.\n", x);
3004 exit(1);
3006 if ((x = ast_wait_for_input(fd, 300)) < 0) {
3007 ast_log(LOG_ERROR, "You have DAHDI built and drivers loaded, but the DAHDI timer could not be polled during the DAHDI timer test.\n");
3008 exit(1);
3010 if (!x) {
3011 const char dahdi_timer_error[] = {
3012 "Asterisk has detected a problem with your DAHDI configuration and will shutdown for your protection. You have options:"
3013 "\n\t1. You only have to compile DAHDI support into Asterisk if you need it. One option is to recompile without DAHDI support."
3014 "\n\t2. You only have to load DAHDI drivers if you want to take advantage of DAHDI services. One option is to unload DAHDI modules if you don't need them."
3015 "\n\t3. If you need DAHDI services, you must correctly configure DAHDI."
3017 ast_log(LOG_ERROR, "%s\n", dahdi_timer_error);
3018 exit(1);
3020 close(fd);
3024 #endif
3025 threadstorage_init();
3027 astobj2_init();
3029 ast_autoservice_init();
3031 if (load_modules(1)) {
3032 printf(term_quit());
3033 exit(1);
3036 if (dnsmgr_init()) {
3037 printf(term_quit());
3038 exit(1);
3041 ast_http_init();
3043 ast_channels_init();
3045 if (init_manager()) {
3046 printf(term_quit());
3047 exit(1);
3050 if (ast_cdr_engine_init()) {
3051 printf(term_quit());
3052 exit(1);
3055 if (ast_device_state_engine_init()) {
3056 printf(term_quit());
3057 exit(1);
3060 ast_rtp_init();
3062 ast_udptl_init();
3064 if (ast_image_init()) {
3065 printf(term_quit());
3066 exit(1);
3069 if (ast_file_init()) {
3070 printf(term_quit());
3071 exit(1);
3074 if (load_pbx()) {
3075 printf(term_quit());
3076 exit(1);
3079 if (init_framer()) {
3080 printf(term_quit());
3081 exit(1);
3084 if (astdb_init()) {
3085 printf(term_quit());
3086 exit(1);
3089 if (ast_enum_init()) {
3090 printf(term_quit());
3091 exit(1);
3094 if (load_modules(0)) {
3095 printf(term_quit());
3096 exit(1);
3099 dnsmgr_start_refresh();
3101 /* We might have the option of showing a console, but for now just
3102 do nothing... */
3103 if (ast_opt_console && !option_verbose)
3104 ast_verbose(" ]\n");
3105 if (option_verbose || ast_opt_console)
3106 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
3107 if (ast_opt_no_fork)
3108 consolethread = pthread_self();
3110 if (pipe(sig_alert_pipe))
3111 sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
3113 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
3114 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
3116 #ifdef __AST_DEBUG_MALLOC
3117 __ast_mm_init();
3118 #endif
3120 time(&ast_startuptime);
3121 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
3123 if (ast_opt_console) {
3124 /* Console stuff now... */
3125 /* Register our quit function */
3126 char title[256];
3127 pthread_attr_t attr;
3128 pthread_t dont_care;
3130 pthread_attr_init(&attr);
3131 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3132 ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);
3133 pthread_attr_destroy(&attr);
3135 set_icon("Asterisk");
3136 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
3137 set_title(title);
3139 for (;;) {
3140 buf = (char *)el_gets(el, &num);
3142 if (!buf && write(1, "", 1) < 0)
3143 goto lostterm;
3145 if (buf) {
3146 if (buf[strlen(buf)-1] == '\n')
3147 buf[strlen(buf)-1] = '\0';
3149 consolehandler((char *)buf);
3150 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
3151 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
3152 /* Whoa, stdout disappeared from under us... Make /dev/null's */
3153 int fd;
3154 fd = open("/dev/null", O_RDWR);
3155 if (fd > -1) {
3156 dup2(fd, STDOUT_FILENO);
3157 dup2(fd, STDIN_FILENO);
3158 } else
3159 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
3160 break;
3165 monitor_sig_flags(NULL);
3167 lostterm:
3168 return 0;