Merged revisions 111125 via svnmerge from
[asterisk-bristuff.git] / main / asterisk.c
blobb4eeedb5c740a9cf26372b6b90008f99ba50b64e
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>
83 #ifdef linux
84 #include <sys/prctl.h>
85 #ifdef HAVE_CAP
86 #include <sys/capability.h>
87 #endif /* HAVE_CAP */
88 #endif /* linux */
89 #include <regex.h>
91 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
92 #include <netdb.h>
93 #if defined(SOLARIS)
94 int daemon(int, int); /* defined in libresolv of all places */
95 #endif
96 #endif
98 #include "asterisk/logger.h"
99 #include "asterisk/options.h"
100 #include "asterisk/cli.h"
101 #include "asterisk/channel.h"
102 #include "asterisk/ulaw.h"
103 #include "asterisk/alaw.h"
104 #include "asterisk/callerid.h"
105 #include "asterisk/image.h"
106 #include "asterisk/tdd.h"
107 #include "asterisk/term.h"
108 #include "asterisk/manager.h"
109 #include "asterisk/cdr.h"
110 #include "asterisk/pbx.h"
111 #include "asterisk/enum.h"
112 #include "asterisk/rtp.h"
113 #include "asterisk/http.h"
114 #include "asterisk/udptl.h"
115 #include "asterisk/app.h"
116 #include "asterisk/lock.h"
117 #include "asterisk/utils.h"
118 #include "asterisk/file.h"
119 #include "asterisk/io.h"
120 #include "asterisk/lock.h"
121 #include "editline/histedit.h"
122 #include "asterisk/config.h"
123 #include "asterisk/version.h"
124 #include "asterisk/linkedlists.h"
125 #include "asterisk/devicestate.h"
126 #include "asterisk/module.h"
128 #include "asterisk/doxyref.h" /* Doxygen documentation */
130 #include "../defaults.h"
132 #ifndef AF_LOCAL
133 #define AF_LOCAL AF_UNIX
134 #define PF_LOCAL PF_UNIX
135 #endif
137 #define AST_MAX_CONNECTS 128
138 #define NUM_MSGS 64
140 /*! \brief Welcome message when starting a CLI interface */
141 #define WELCOME_MESSAGE \
142 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008 Digium, Inc. and others.\n"); \
143 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
144 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
145 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
146 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
147 ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
148 ast_verbose("=========================================================================\n")
150 /*! \defgroup main_options Main Configuration Options
151 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
152 the operating system command line when starting Asterisk
153 Some of them can be changed in the CLI
155 /*! @{ */
157 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
159 int option_verbose; /*!< Verbosity level */
160 int option_debug; /*!< Debug level */
162 double option_maxload; /*!< Max load avg on system */
163 int option_maxcalls; /*!< Max number of active calls */
165 /*! @} */
167 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
168 char debug_filename[AST_FILENAME_MAX] = "";
170 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
171 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
172 pid_t ast_mainpid;
173 struct console {
174 int fd; /*!< File descriptor */
175 int p[2]; /*!< Pipe */
176 pthread_t t; /*!< Thread of handler */
177 int mute; /*!< Is the console muted for logs */
180 struct ast_atexit {
181 void (*func)(void);
182 AST_LIST_ENTRY(ast_atexit) list;
185 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
187 time_t ast_startuptime;
188 time_t ast_lastreloadtime;
190 static History *el_hist;
191 static EditLine *el;
192 static char *remotehostname;
194 struct console consoles[AST_MAX_CONNECTS];
196 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
198 static int ast_el_add_history(char *);
199 static int ast_el_read_history(char *);
200 static int ast_el_write_history(char *);
202 char ast_config_AST_CONFIG_DIR[PATH_MAX];
203 char ast_config_AST_CONFIG_FILE[PATH_MAX];
204 char ast_config_AST_MODULE_DIR[PATH_MAX];
205 char ast_config_AST_SPOOL_DIR[PATH_MAX];
206 char ast_config_AST_MONITOR_DIR[PATH_MAX];
207 char ast_config_AST_VAR_DIR[PATH_MAX];
208 char ast_config_AST_DATA_DIR[PATH_MAX];
209 char ast_config_AST_LOG_DIR[PATH_MAX];
210 char ast_config_AST_AGI_DIR[PATH_MAX];
211 char ast_config_AST_DB[PATH_MAX];
212 char ast_config_AST_KEY_DIR[PATH_MAX];
213 char ast_config_AST_PID[PATH_MAX];
214 char ast_config_AST_SOCKET[PATH_MAX];
215 char ast_config_AST_RUN_DIR[PATH_MAX];
216 char ast_config_AST_RUN_USER[PATH_MAX];
217 char ast_config_AST_RUN_GROUP[PATH_MAX];
218 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
219 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
220 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
221 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
222 char ast_config_AST_SYSTEM_NAME[20] = "";
224 extern const char *ast_build_hostname;
225 extern const char *ast_build_kernel;
226 extern const char *ast_build_machine;
227 extern const char *ast_build_os;
228 extern const char *ast_build_date;
229 extern const char *ast_build_user;
231 static char *_argv[256];
232 static int shuttingdown;
233 static int restartnow;
234 static pthread_t consolethread = AST_PTHREADT_NULL;
236 static char randompool[256];
238 static int sig_alert_pipe[2] = { -1, -1 };
239 static struct {
240 unsigned int need_reload:1;
241 unsigned int need_quit:1;
242 } sig_flags;
244 #if !defined(LOW_MEMORY)
245 struct file_version {
246 AST_LIST_ENTRY(file_version) list;
247 const char *file;
248 char *version;
251 static AST_LIST_HEAD_STATIC(file_versions, file_version);
253 void ast_register_file_version(const char *file, const char *version)
255 struct file_version *new;
256 char *work;
257 size_t version_length;
259 work = ast_strdupa(version);
260 work = ast_strip(ast_strip_quoted(work, "$", "$"));
261 version_length = strlen(work) + 1;
263 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
264 return;
266 new->file = file;
267 new->version = (char *) new + sizeof(*new);
268 memcpy(new->version, work, version_length);
269 AST_LIST_LOCK(&file_versions);
270 AST_LIST_INSERT_HEAD(&file_versions, new, list);
271 AST_LIST_UNLOCK(&file_versions);
274 void ast_unregister_file_version(const char *file)
276 struct file_version *find;
278 AST_LIST_LOCK(&file_versions);
279 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
280 if (!strcasecmp(find->file, file)) {
281 AST_LIST_REMOVE_CURRENT(&file_versions, list);
282 break;
285 AST_LIST_TRAVERSE_SAFE_END;
286 AST_LIST_UNLOCK(&file_versions);
287 if (find)
288 free(find);
291 struct thread_list_t {
292 AST_LIST_ENTRY(thread_list_t) list;
293 char *name;
294 pthread_t id;
297 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
299 static char show_threads_help[] =
300 "Usage: core show threads\n"
301 " List threads currently active in the system.\n";
303 void ast_register_thread(char *name)
305 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
307 if (!new)
308 return;
309 new->id = pthread_self();
310 new->name = name; /* steal the allocated memory for the thread name */
311 AST_LIST_LOCK(&thread_list);
312 AST_LIST_INSERT_HEAD(&thread_list, new, list);
313 AST_LIST_UNLOCK(&thread_list);
316 void ast_unregister_thread(void *id)
318 struct thread_list_t *x;
320 AST_LIST_LOCK(&thread_list);
321 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
322 if ((void *) x->id == id) {
323 AST_LIST_REMOVE_CURRENT(&thread_list, list);
324 break;
327 AST_LIST_TRAVERSE_SAFE_END;
328 AST_LIST_UNLOCK(&thread_list);
329 if (x) {
330 free(x->name);
331 free(x);
335 static int handle_show_threads(int fd, int argc, char *argv[])
337 int count = 0;
338 struct thread_list_t *cur;
340 AST_LIST_LOCK(&thread_list);
341 AST_LIST_TRAVERSE(&thread_list, cur, list) {
342 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
343 count++;
345 AST_LIST_UNLOCK(&thread_list);
346 ast_cli(fd, "%d threads listed.\n", count);
347 return 0;
350 struct profile_entry {
351 const char *name;
352 uint64_t scale; /* if non-zero, values are scaled by this */
353 int64_t mark;
354 int64_t value;
355 int64_t events;
358 struct profile_data {
359 int entries;
360 int max_size;
361 struct profile_entry e[0];
364 static struct profile_data *prof_data;
366 /*! \brief allocates a counter with a given name and scale.
367 * \return Returns the identifier of the counter.
369 int ast_add_profile(const char *name, uint64_t scale)
371 int l = sizeof(struct profile_data);
372 int n = 10; /* default entries */
374 if (prof_data == NULL) {
375 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
376 if (prof_data == NULL)
377 return -1;
378 prof_data->entries = 0;
379 prof_data->max_size = n;
381 if (prof_data->entries >= prof_data->max_size) {
382 void *p;
383 n = prof_data->max_size + 20;
384 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
385 if (p == NULL)
386 return -1;
387 prof_data = p;
388 prof_data->max_size = n;
390 n = prof_data->entries++;
391 prof_data->e[n].name = ast_strdup(name);
392 prof_data->e[n].value = 0;
393 prof_data->e[n].events = 0;
394 prof_data->e[n].mark = 0;
395 prof_data->e[n].scale = scale;
396 return n;
399 int64_t ast_profile(int i, int64_t delta)
401 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
402 return 0;
403 if (prof_data->e[i].scale > 1)
404 delta /= prof_data->e[i].scale;
405 prof_data->e[i].value += delta;
406 prof_data->e[i].events++;
407 return prof_data->e[i].value;
410 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
411 #if defined(__FreeBSD__)
412 #include <machine/cpufunc.h>
413 #elif defined(linux)
414 static __inline uint64_t
415 rdtsc(void)
417 uint64_t rv;
419 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
420 return (rv);
422 #endif
423 #else /* supply a dummy function on other platforms */
424 static __inline uint64_t
425 rdtsc(void)
427 return 0;
429 #endif
431 int64_t ast_mark(int i, int startstop)
433 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
434 return 0;
435 if (startstop == 1)
436 prof_data->e[i].mark = rdtsc();
437 else {
438 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
439 if (prof_data->e[i].scale > 1)
440 prof_data->e[i].mark /= prof_data->e[i].scale;
441 prof_data->e[i].value += prof_data->e[i].mark;
442 prof_data->e[i].events++;
444 return prof_data->e[i].mark;
447 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
449 int i, min, max;
450 char *search = NULL;
452 if (prof_data == NULL)
453 return 0;
455 min = 0;
456 max = prof_data->entries;
457 if (argc >= 3) { /* specific entries */
458 if (isdigit(argv[2][0])) {
459 min = atoi(argv[2]);
460 if (argc == 4 && strcmp(argv[3], "-"))
461 max = atoi(argv[3]);
462 } else
463 search = argv[2];
465 if (max > prof_data->entries)
466 max = prof_data->entries;
467 if (!strcmp(argv[0], "clear")) {
468 for (i= min; i < max; i++) {
469 if (!search || strstr(prof_data->e[i].name, search)) {
470 prof_data->e[i].value = 0;
471 prof_data->e[i].events = 0;
474 return 0;
476 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
477 prof_data->entries, prof_data->max_size);
478 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
479 "Value", "Average", "Name");
480 for (i = min; i < max; i++) {
481 struct profile_entry *e = &prof_data->e[i];
482 if (!search || strstr(prof_data->e[i].name, search))
483 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
485 (long)e->scale,
486 (long)e->events, (long long)e->value,
487 (long long)(e->events ? e->value / e->events : e->value),
488 e->name);
490 return 0;
493 static int handle_show_profile(int fd, int argc, char *argv[])
495 int i, min, max;
496 char *search = NULL;
498 if (prof_data == NULL)
499 return 0;
501 min = 0;
502 max = prof_data->entries;
503 if (argc > 3) { /* specific entries */
504 if (isdigit(argv[3][0])) {
505 min = atoi(argv[3]);
506 if (argc == 5 && strcmp(argv[4], "-"))
507 max = atoi(argv[4]);
508 } else
509 search = argv[3];
511 if (max > prof_data->entries)
512 max = prof_data->entries;
513 if (!strcmp(argv[1], "clear")) {
514 for (i= min; i < max; i++) {
515 if (!search || strstr(prof_data->e[i].name, search)) {
516 prof_data->e[i].value = 0;
517 prof_data->e[i].events = 0;
520 return 0;
522 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
523 prof_data->entries, prof_data->max_size);
524 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
525 "Value", "Average", "Name");
526 for (i = min; i < max; i++) {
527 struct profile_entry *e = &prof_data->e[i];
528 if (!search || strstr(prof_data->e[i].name, search))
529 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
531 (long)e->scale,
532 (long)e->events, (long long)e->value,
533 (long long)(e->events ? e->value / e->events : e->value),
534 e->name);
536 return 0;
539 static char show_version_files_help[] =
540 "Usage: core show file version [like <pattern>]\n"
541 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
542 " Optional regular expression pattern is used to filter the file list.\n";
544 /*! \brief CLI command to list module versions */
545 static int handle_show_version_files_deprecated(int fd, int argc, char *argv[])
547 #define FORMAT "%-25.25s %-40.40s\n"
548 struct file_version *iterator;
549 regex_t regexbuf;
550 int havepattern = 0;
551 int havename = 0;
552 int count_files = 0;
554 switch (argc) {
555 case 5:
556 if (!strcasecmp(argv[3], "like")) {
557 if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
558 return RESULT_SHOWUSAGE;
559 havepattern = 1;
560 } else
561 return RESULT_SHOWUSAGE;
562 break;
563 case 4:
564 havename = 1;
565 break;
566 case 3:
567 break;
568 default:
569 return RESULT_SHOWUSAGE;
572 ast_cli(fd, FORMAT, "File", "Revision");
573 ast_cli(fd, FORMAT, "----", "--------");
574 AST_LIST_LOCK(&file_versions);
575 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
576 if (havename && strcasecmp(iterator->file, argv[3]))
577 continue;
579 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
580 continue;
582 ast_cli(fd, FORMAT, iterator->file, iterator->version);
583 count_files++;
584 if (havename)
585 break;
587 AST_LIST_UNLOCK(&file_versions);
588 if (!havename) {
589 ast_cli(fd, "%d files listed.\n", count_files);
592 if (havepattern)
593 regfree(&regexbuf);
595 return RESULT_SUCCESS;
596 #undef FORMAT
599 static int handle_show_version_files(int fd, int argc, char *argv[])
601 #define FORMAT "%-25.25s %-40.40s\n"
602 struct file_version *iterator;
603 regex_t regexbuf;
604 int havepattern = 0;
605 int havename = 0;
606 int count_files = 0;
608 switch (argc) {
609 case 6:
610 if (!strcasecmp(argv[4], "like")) {
611 if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
612 return RESULT_SHOWUSAGE;
613 havepattern = 1;
614 } else
615 return RESULT_SHOWUSAGE;
616 break;
617 case 5:
618 havename = 1;
619 break;
620 case 4:
621 break;
622 default:
623 return RESULT_SHOWUSAGE;
626 ast_cli(fd, FORMAT, "File", "Revision");
627 ast_cli(fd, FORMAT, "----", "--------");
628 AST_LIST_LOCK(&file_versions);
629 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
630 if (havename && strcasecmp(iterator->file, argv[4]))
631 continue;
633 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
634 continue;
636 ast_cli(fd, FORMAT, iterator->file, iterator->version);
637 count_files++;
638 if (havename)
639 break;
641 AST_LIST_UNLOCK(&file_versions);
642 if (!havename) {
643 ast_cli(fd, "%d files listed.\n", count_files);
646 if (havepattern)
647 regfree(&regexbuf);
649 return RESULT_SUCCESS;
650 #undef FORMAT
653 static char *complete_show_version_files_deprecated(const char *line, const char *word, int pos, int state)
655 struct file_version *find;
656 int which = 0;
657 char *ret = NULL;
658 int matchlen = strlen(word);
660 if (pos != 3)
661 return NULL;
663 AST_LIST_LOCK(&file_versions);
664 AST_LIST_TRAVERSE(&file_versions, find, list) {
665 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
666 ret = ast_strdup(find->file);
667 break;
670 AST_LIST_UNLOCK(&file_versions);
672 return ret;
675 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
677 struct file_version *find;
678 int which = 0;
679 char *ret = NULL;
680 int matchlen = strlen(word);
682 if (pos != 4)
683 return NULL;
685 AST_LIST_LOCK(&file_versions);
686 AST_LIST_TRAVERSE(&file_versions, find, list) {
687 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
688 ret = ast_strdup(find->file);
689 break;
692 AST_LIST_UNLOCK(&file_versions);
694 return ret;
697 #endif /* ! LOW_MEMORY */
699 int ast_register_atexit(void (*func)(void))
701 struct ast_atexit *ae;
703 if (!(ae = ast_calloc(1, sizeof(*ae))))
704 return -1;
706 ae->func = func;
708 ast_unregister_atexit(func);
710 AST_LIST_LOCK(&atexits);
711 AST_LIST_INSERT_HEAD(&atexits, ae, list);
712 AST_LIST_UNLOCK(&atexits);
714 return 0;
717 void ast_unregister_atexit(void (*func)(void))
719 struct ast_atexit *ae = NULL;
721 AST_LIST_LOCK(&atexits);
722 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
723 if (ae->func == func) {
724 AST_LIST_REMOVE_CURRENT(&atexits, list);
725 break;
728 AST_LIST_TRAVERSE_SAFE_END
729 AST_LIST_UNLOCK(&atexits);
731 if (ae)
732 free(ae);
735 static int fdprint(int fd, const char *s)
737 return write(fd, s, strlen(s) + 1);
740 /*! \brief NULL handler so we can collect the child exit status */
741 static void null_sig_handler(int signal)
746 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
747 /*! \brief Keep track of how many threads are currently trying to wait*() on
748 * a child process */
749 static unsigned int safe_system_level = 0;
750 static void *safe_system_prev_handler;
752 void ast_replace_sigchld(void)
754 unsigned int level;
756 ast_mutex_lock(&safe_system_lock);
757 level = safe_system_level++;
759 /* only replace the handler if it has not already been done */
760 if (level == 0)
761 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
763 ast_mutex_unlock(&safe_system_lock);
766 void ast_unreplace_sigchld(void)
768 unsigned int level;
770 ast_mutex_lock(&safe_system_lock);
771 level = --safe_system_level;
773 /* only restore the handler if we are the last one */
774 if (level == 0)
775 signal(SIGCHLD, safe_system_prev_handler);
777 ast_mutex_unlock(&safe_system_lock);
780 int ast_safe_system(const char *s)
782 pid_t pid;
783 #ifdef HAVE_WORKING_FORK
784 int x;
785 #endif
786 int res;
787 struct rusage rusage;
788 int status;
790 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
791 ast_replace_sigchld();
793 #ifdef HAVE_WORKING_FORK
794 pid = fork();
795 #else
796 pid = vfork();
797 #endif
799 if (pid == 0) {
800 #ifdef HAVE_WORKING_FORK
801 if (ast_opt_high_priority)
802 ast_set_priority(0);
803 /* Close file descriptors and launch system command */
804 for (x = STDERR_FILENO + 1; x < 4096; x++)
805 close(x);
806 #endif
807 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
808 _exit(1);
809 } else if (pid > 0) {
810 for(;;) {
811 res = wait4(pid, &status, 0, &rusage);
812 if (res > -1) {
813 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
814 break;
815 } else if (errno != EINTR)
816 break;
818 } else {
819 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
820 res = -1;
823 ast_unreplace_sigchld();
824 #else
825 res = -1;
826 #endif
828 return res;
832 * \brief mute or unmute a console from logging
834 void ast_console_toggle_mute(int fd, int silent) {
835 int x;
836 for (x = 0;x < AST_MAX_CONNECTS; x++) {
837 if (fd == consoles[x].fd) {
838 if (consoles[x].mute) {
839 consoles[x].mute = 0;
840 if (!silent)
841 ast_cli(fd, "Console is not muted anymore.\n");
842 } else {
843 consoles[x].mute = 1;
844 if (!silent)
845 ast_cli(fd, "Console is muted.\n");
847 return;
850 ast_cli(fd, "Couldn't find remote console.\n");
854 * \brief log the string to all attached console clients
856 static void ast_network_puts_mutable(const char *string)
858 int x;
859 for (x = 0;x < AST_MAX_CONNECTS; x++) {
860 if (consoles[x].mute)
861 continue;
862 if (consoles[x].fd > -1)
863 fdprint(consoles[x].p[1], string);
868 * \brief log the string to the console, and all attached
869 * console clients
871 void ast_console_puts_mutable(const char *string)
873 fputs(string, stdout);
874 fflush(stdout);
875 ast_network_puts_mutable(string);
879 * \brief write the string to all attached console clients
881 static void ast_network_puts(const char *string)
883 int x;
884 for (x=0; x < AST_MAX_CONNECTS; x++) {
885 if (consoles[x].fd > -1)
886 fdprint(consoles[x].p[1], string);
891 * write the string to the console, and all attached
892 * console clients
894 void ast_console_puts(const char *string)
896 fputs(string, stdout);
897 fflush(stdout);
898 ast_network_puts(string);
901 static void network_verboser(const char *s)
903 ast_network_puts_mutable(s);
906 static pthread_t lthread;
908 static void *netconsole(void *vconsole)
910 struct console *con = vconsole;
911 char hostname[MAXHOSTNAMELEN] = "";
912 char tmp[512];
913 int res;
914 struct pollfd fds[2];
916 if (gethostname(hostname, sizeof(hostname)-1))
917 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
918 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
919 fdprint(con->fd, tmp);
920 for(;;) {
921 fds[0].fd = con->fd;
922 fds[0].events = POLLIN;
923 fds[0].revents = 0;
924 fds[1].fd = con->p[0];
925 fds[1].events = POLLIN;
926 fds[1].revents = 0;
928 res = poll(fds, 2, -1);
929 if (res < 0) {
930 if (errno != EINTR)
931 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
932 continue;
934 if (fds[0].revents) {
935 res = read(con->fd, tmp, sizeof(tmp));
936 if (res < 1) {
937 break;
939 tmp[res] = 0;
940 ast_cli_command_multiple(con->fd, res, tmp);
942 if (fds[1].revents) {
943 res = read(con->p[0], tmp, sizeof(tmp));
944 if (res < 1) {
945 ast_log(LOG_ERROR, "read returned %d\n", res);
946 break;
948 res = write(con->fd, tmp, res);
949 if (res < 1)
950 break;
953 if (option_verbose > 2)
954 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
955 close(con->fd);
956 close(con->p[0]);
957 close(con->p[1]);
958 con->fd = -1;
960 return NULL;
963 static void *listener(void *unused)
965 struct sockaddr_un sunaddr;
966 int s;
967 socklen_t len;
968 int x;
969 int flags;
970 struct pollfd fds[1];
971 pthread_attr_t attr;
972 pthread_attr_init(&attr);
973 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
974 for (;;) {
975 if (ast_socket < 0)
976 return NULL;
977 fds[0].fd = ast_socket;
978 fds[0].events = POLLIN;
979 s = poll(fds, 1, -1);
980 pthread_testcancel();
981 if (s < 0) {
982 if (errno != EINTR)
983 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
984 continue;
986 len = sizeof(sunaddr);
987 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
988 if (s < 0) {
989 if (errno != EINTR)
990 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
991 } else {
992 for (x = 0; x < AST_MAX_CONNECTS; x++) {
993 if (consoles[x].fd < 0) {
994 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
995 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
996 consoles[x].fd = -1;
997 fdprint(s, "Server failed to create pipe\n");
998 close(s);
999 break;
1001 flags = fcntl(consoles[x].p[1], F_GETFL);
1002 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1003 consoles[x].fd = s;
1004 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1005 if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) {
1006 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1007 close(consoles[x].p[0]);
1008 close(consoles[x].p[1]);
1009 consoles[x].fd = -1;
1010 fdprint(s, "Server failed to spawn thread\n");
1011 close(s);
1013 break;
1016 if (x >= AST_MAX_CONNECTS) {
1017 fdprint(s, "No more connections allowed\n");
1018 ast_log(LOG_WARNING, "No more connections allowed\n");
1019 close(s);
1020 } else if (consoles[x].fd > -1) {
1021 if (option_verbose > 2)
1022 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
1026 return NULL;
1029 static int ast_makesocket(void)
1031 struct sockaddr_un sunaddr;
1032 int res;
1033 int x;
1034 uid_t uid = -1;
1035 gid_t gid = -1;
1037 for (x = 0; x < AST_MAX_CONNECTS; x++)
1038 consoles[x].fd = -1;
1039 unlink(ast_config_AST_SOCKET);
1040 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1041 if (ast_socket < 0) {
1042 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1043 return -1;
1045 memset(&sunaddr, 0, sizeof(sunaddr));
1046 sunaddr.sun_family = AF_LOCAL;
1047 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1048 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1049 if (res) {
1050 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1051 close(ast_socket);
1052 ast_socket = -1;
1053 return -1;
1055 res = listen(ast_socket, 2);
1056 if (res < 0) {
1057 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1058 close(ast_socket);
1059 ast_socket = -1;
1060 return -1;
1062 ast_register_verbose(network_verboser);
1063 ast_pthread_create_background(&lthread, NULL, listener, NULL);
1065 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1066 struct passwd *pw;
1067 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
1068 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1069 } else {
1070 uid = pw->pw_uid;
1074 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1075 struct group *grp;
1076 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
1077 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1078 } else {
1079 gid = grp->gr_gid;
1083 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1084 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1086 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1087 int p1;
1088 mode_t p;
1089 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
1090 p = p1;
1091 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1092 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1095 return 0;
1098 static int ast_tryconnect(void)
1100 struct sockaddr_un sunaddr;
1101 int res;
1102 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1103 if (ast_consock < 0) {
1104 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1105 return 0;
1107 memset(&sunaddr, 0, sizeof(sunaddr));
1108 sunaddr.sun_family = AF_LOCAL;
1109 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1110 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1111 if (res) {
1112 close(ast_consock);
1113 ast_consock = -1;
1114 return 0;
1115 } else
1116 return 1;
1119 /*! \brief Urgent handler
1121 Called by soft_hangup to interrupt the poll, read, or other
1122 system call. We don't actually need to do anything though.
1123 Remember: Cannot EVER ast_log from within a signal handler
1125 static void urg_handler(int num)
1127 signal(num, urg_handler);
1128 return;
1131 static void hup_handler(int num)
1133 int a = 0;
1134 if (option_verbose > 1)
1135 printf("Received HUP signal -- Reloading configs\n");
1136 if (restartnow)
1137 execvp(_argv[0], _argv);
1138 sig_flags.need_reload = 1;
1139 if (sig_alert_pipe[1] != -1)
1140 write(sig_alert_pipe[1], &a, sizeof(a));
1141 signal(num, hup_handler);
1144 static void child_handler(int sig)
1146 /* Must not ever ast_log or ast_verbose within signal handler */
1147 int n, status;
1150 * Reap all dead children -- not just one
1152 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1154 if (n == 0 && option_debug)
1155 printf("Huh? Child handler, but nobody there?\n");
1156 signal(sig, child_handler);
1159 /*! \brief Set an X-term or screen title */
1160 static void set_title(char *text)
1162 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1163 fprintf(stdout, "\033]2;%s\007", text);
1166 static void set_icon(char *text)
1168 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1169 fprintf(stdout, "\033]1;%s\007", text);
1172 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1173 else. If your PBX has heavy activity on it, this is a good thing. */
1174 int ast_set_priority(int pri)
1176 struct sched_param sched;
1177 memset(&sched, 0, sizeof(sched));
1178 #ifdef __linux__
1179 if (pri) {
1180 sched.sched_priority = 10;
1181 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1182 ast_log(LOG_WARNING, "Unable to set high priority\n");
1183 return -1;
1184 } else
1185 if (option_verbose)
1186 ast_verbose("Set to realtime thread\n");
1187 } else {
1188 sched.sched_priority = 0;
1189 /* According to the manpage, these parameters can never fail. */
1190 sched_setscheduler(0, SCHED_OTHER, &sched);
1192 #else
1193 if (pri) {
1194 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1195 ast_log(LOG_WARNING, "Unable to set high priority\n");
1196 return -1;
1197 } else
1198 if (option_verbose)
1199 ast_verbose("Set to high priority\n");
1200 } else {
1201 /* According to the manpage, these parameters can never fail. */
1202 setpriority(PRIO_PROCESS, 0, 0);
1204 #endif
1205 return 0;
1208 static void ast_run_atexits(void)
1210 struct ast_atexit *ae;
1211 AST_LIST_LOCK(&atexits);
1212 AST_LIST_TRAVERSE(&atexits, ae, list) {
1213 if (ae->func)
1214 ae->func();
1216 AST_LIST_UNLOCK(&atexits);
1219 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1221 char filename[80] = "";
1222 time_t s,e;
1223 int x;
1224 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1225 ast_cdr_engine_term();
1226 if (safeshutdown) {
1227 shuttingdown = 1;
1228 if (!nice) {
1229 /* Begin shutdown routine, hanging up active channels */
1230 ast_begin_shutdown(1);
1231 if (option_verbose && ast_opt_console)
1232 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1233 time(&s);
1234 for (;;) {
1235 time(&e);
1236 /* Wait up to 15 seconds for all channels to go away */
1237 if ((e - s) > 15)
1238 break;
1239 if (!ast_active_channels())
1240 break;
1241 if (!shuttingdown)
1242 break;
1243 /* Sleep 1/10 of a second */
1244 usleep(100000);
1246 } else {
1247 if (nice < 2)
1248 ast_begin_shutdown(0);
1249 if (option_verbose && ast_opt_console)
1250 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1251 for (;;) {
1252 if (!ast_active_channels())
1253 break;
1254 if (!shuttingdown)
1255 break;
1256 sleep(1);
1260 if (!shuttingdown) {
1261 if (option_verbose && ast_opt_console)
1262 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1263 return;
1266 if (nice)
1267 ast_module_shutdown();
1269 if (ast_opt_console || ast_opt_remote) {
1270 if (getenv("HOME"))
1271 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1272 if (!ast_strlen_zero(filename))
1273 ast_el_write_history(filename);
1274 if (el != NULL)
1275 el_end(el);
1276 if (el_hist != NULL)
1277 history_end(el_hist);
1279 if (option_verbose)
1280 ast_verbose("Executing last minute cleanups\n");
1281 ast_run_atexits();
1282 /* Called on exit */
1283 if (option_verbose && ast_opt_console)
1284 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1285 if (option_debug)
1286 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1287 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1288 if (ast_socket > -1) {
1289 pthread_cancel(lthread);
1290 close(ast_socket);
1291 ast_socket = -1;
1292 unlink(ast_config_AST_SOCKET);
1294 if (ast_consock > -1)
1295 close(ast_consock);
1296 if (!ast_opt_remote)
1297 unlink(ast_config_AST_PID);
1298 printf(term_quit());
1299 if (restart) {
1300 if (option_verbose || ast_opt_console)
1301 ast_verbose("Preparing for Asterisk restart...\n");
1302 /* Mark all FD's for closing on exec */
1303 for (x=3; x < 32768; x++) {
1304 fcntl(x, F_SETFD, FD_CLOEXEC);
1306 if (option_verbose || ast_opt_console)
1307 ast_verbose("Asterisk is now restarting...\n");
1308 restartnow = 1;
1310 /* close logger */
1311 close_logger();
1313 /* If there is a consolethread running send it a SIGHUP
1314 so it can execvp, otherwise we can do it ourselves */
1315 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1316 pthread_kill(consolethread, SIGHUP);
1317 /* Give the signal handler some time to complete */
1318 sleep(2);
1319 } else
1320 execvp(_argv[0], _argv);
1322 } else {
1323 /* close logger */
1324 close_logger();
1326 exit(0);
1329 static void __quit_handler(int num)
1331 int a = 0;
1332 sig_flags.need_quit = 1;
1333 if (sig_alert_pipe[1] != -1)
1334 write(sig_alert_pipe[1], &a, sizeof(a));
1335 /* There is no need to restore the signal handler here, since the app
1336 * is going to exit */
1339 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1341 const char *c;
1342 if (!strncmp(s, cmp, strlen(cmp))) {
1343 c = s + strlen(cmp);
1344 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1345 return c;
1347 return NULL;
1350 static void console_verboser(const char *s)
1352 char tmp[80];
1353 const char *c = NULL;
1355 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1356 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1357 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1358 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1359 fputs(tmp, stdout);
1360 fputs(c, stdout);
1361 } else
1362 fputs(s, stdout);
1364 fflush(stdout);
1366 /* Wake up a poll()ing console */
1367 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1368 pthread_kill(consolethread, SIGURG);
1371 static int ast_all_zeros(char *s)
1373 while (*s) {
1374 if (*s > 32)
1375 return 0;
1376 s++;
1378 return 1;
1381 static void consolehandler(char *s)
1383 printf(term_end());
1384 fflush(stdout);
1386 /* Called when readline data is available */
1387 if (!ast_all_zeros(s))
1388 ast_el_add_history(s);
1389 /* The real handler for bang */
1390 if (s[0] == '!') {
1391 if (s[1])
1392 ast_safe_system(s+1);
1393 else
1394 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1395 } else
1396 ast_cli_command(STDOUT_FILENO, s);
1399 static int remoteconsolehandler(char *s)
1401 int ret = 0;
1403 /* Called when readline data is available */
1404 if (!ast_all_zeros(s))
1405 ast_el_add_history(s);
1406 /* The real handler for bang */
1407 if (s[0] == '!') {
1408 if (s[1])
1409 ast_safe_system(s+1);
1410 else
1411 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1412 ret = 1;
1414 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1415 (s[4] == '\0' || isspace(s[4]))) {
1416 quit_handler(0, 0, 0, 0);
1417 ret = 1;
1420 return ret;
1423 static char abort_halt_help[] =
1424 "Usage: abort shutdown\n"
1425 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1426 " call operations.\n";
1428 static char shutdown_now_help[] =
1429 "Usage: stop now\n"
1430 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1432 static char shutdown_gracefully_help[] =
1433 "Usage: stop gracefully\n"
1434 " Causes Asterisk to not accept new calls, and exit when all\n"
1435 " active calls have terminated normally.\n";
1437 static char shutdown_when_convenient_help[] =
1438 "Usage: stop when convenient\n"
1439 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1441 static char restart_now_help[] =
1442 "Usage: restart now\n"
1443 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1444 " restart.\n";
1446 static char restart_gracefully_help[] =
1447 "Usage: restart gracefully\n"
1448 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1449 " restart when all active calls have ended.\n";
1451 static char restart_when_convenient_help[] =
1452 "Usage: restart when convenient\n"
1453 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1455 static char bang_help[] =
1456 "Usage: !<command>\n"
1457 " Executes a given shell command\n";
1459 static char show_warranty_help[] =
1460 "Usage: core show warranty\n"
1461 " Shows the warranty (if any) for this copy of Asterisk.\n";
1463 static char show_license_help[] =
1464 "Usage: core show license\n"
1465 " Shows the license(s) for this copy of Asterisk.\n";
1467 static char version_help[] =
1468 "Usage: core show version\n"
1469 " Shows Asterisk version information.\n";
1471 static int handle_version_deprecated(int fd, int argc, char *argv[])
1473 if (argc != 2)
1474 return RESULT_SHOWUSAGE;
1475 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1476 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1477 ast_build_machine, ast_build_os, ast_build_date);
1478 return RESULT_SUCCESS;
1481 static int handle_version(int fd, int argc, char *argv[])
1483 if (argc != 3)
1484 return RESULT_SHOWUSAGE;
1485 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1486 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1487 ast_build_machine, ast_build_os, ast_build_date);
1488 return RESULT_SUCCESS;
1491 #if 0
1492 static int handle_quit(int fd, int argc, char *argv[])
1494 if (argc != 1)
1495 return RESULT_SHOWUSAGE;
1496 quit_handler(0, 0, 1, 0);
1497 return RESULT_SUCCESS;
1499 #endif
1501 static int handle_shutdown_now(int fd, int argc, char *argv[])
1503 if (argc != 2)
1504 return RESULT_SHOWUSAGE;
1505 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1506 return RESULT_SUCCESS;
1509 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1511 if (argc != 2)
1512 return RESULT_SHOWUSAGE;
1513 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1514 return RESULT_SUCCESS;
1517 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1519 if (argc != 3)
1520 return RESULT_SHOWUSAGE;
1521 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1522 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1523 return RESULT_SUCCESS;
1526 static int handle_restart_now(int fd, int argc, char *argv[])
1528 if (argc != 2)
1529 return RESULT_SHOWUSAGE;
1530 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1531 return RESULT_SUCCESS;
1534 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1536 if (argc != 2)
1537 return RESULT_SHOWUSAGE;
1538 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1539 return RESULT_SUCCESS;
1542 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1544 if (argc != 3)
1545 return RESULT_SHOWUSAGE;
1546 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1547 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1548 return RESULT_SUCCESS;
1551 static int handle_abort_halt(int fd, int argc, char *argv[])
1553 if (argc != 2)
1554 return RESULT_SHOWUSAGE;
1555 ast_cancel_shutdown();
1556 shuttingdown = 0;
1557 return RESULT_SUCCESS;
1560 static int handle_bang(int fd, int argc, char *argv[])
1562 return RESULT_SUCCESS;
1564 static const char *warranty_lines[] = {
1565 "\n",
1566 " NO WARRANTY\n",
1567 "\n",
1568 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1569 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1570 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1571 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1572 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1573 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1574 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1575 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1576 "REPAIR OR CORRECTION.\n",
1577 "\n",
1578 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1579 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1580 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1581 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1582 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1583 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1584 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1585 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1586 "POSSIBILITY OF SUCH DAMAGES.\n",
1589 static int show_warranty(int fd, int argc, char *argv[])
1591 int x;
1593 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1594 ast_cli(fd, (char *) warranty_lines[x]);
1596 return RESULT_SUCCESS;
1599 static const char *license_lines[] = {
1600 "\n",
1601 "This program is free software; you can redistribute it and/or modify\n",
1602 "it under the terms of the GNU General Public License version 2 as\n",
1603 "published by the Free Software Foundation.\n",
1604 "\n",
1605 "This program also contains components licensed under other licenses.\n",
1606 "They include:\n",
1607 "\n",
1608 "This program is distributed in the hope that it will be useful,\n",
1609 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1610 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1611 "GNU General Public License for more details.\n",
1612 "\n",
1613 "You should have received a copy of the GNU General Public License\n",
1614 "along with this program; if not, write to the Free Software\n",
1615 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1618 static int show_license(int fd, int argc, char *argv[])
1620 int x;
1622 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1623 ast_cli(fd, (char *) license_lines[x]);
1625 return RESULT_SUCCESS;
1628 #define ASTERISK_PROMPT "*CLI> "
1630 #define ASTERISK_PROMPT2 "%s*CLI> "
1632 static struct ast_cli_entry cli_show_version_deprecated = {
1633 { "show", "version", NULL },
1634 handle_version_deprecated, "Display version info",
1635 version_help };
1637 #if !defined(LOW_MEMORY)
1638 static struct ast_cli_entry cli_show_version_files_deprecated = {
1639 { "show", "version", "files", NULL },
1640 handle_show_version_files_deprecated, NULL,
1641 NULL, complete_show_version_files_deprecated };
1643 static struct ast_cli_entry cli_show_profile_deprecated = {
1644 { "show", "profile", NULL },
1645 handle_show_profile_deprecated, NULL,
1646 NULL };
1648 static struct ast_cli_entry cli_clear_profile_deprecated = {
1649 { "clear", "profile", NULL },
1650 handle_show_profile_deprecated, NULL,
1651 NULL };
1652 #endif /* ! LOW_MEMORY */
1654 static struct ast_cli_entry cli_asterisk[] = {
1655 { { "abort", "halt", NULL },
1656 handle_abort_halt, "Cancel a running halt",
1657 abort_halt_help },
1659 { { "stop", "now", NULL },
1660 handle_shutdown_now, "Shut down Asterisk immediately",
1661 shutdown_now_help },
1663 { { "stop", "gracefully", NULL },
1664 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1665 shutdown_gracefully_help },
1667 { { "stop", "when", "convenient", NULL },
1668 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1669 shutdown_when_convenient_help },
1671 { { "restart", "now", NULL },
1672 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1674 { { "restart", "gracefully", NULL },
1675 handle_restart_gracefully, "Restart Asterisk gracefully",
1676 restart_gracefully_help },
1678 { { "restart", "when", "convenient", NULL },
1679 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1680 restart_when_convenient_help },
1682 { { "core", "show", "warranty", NULL },
1683 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1684 show_warranty_help },
1686 { { "core", "show", "license", NULL },
1687 show_license, "Show the license(s) for this copy of Asterisk",
1688 show_license_help },
1690 { { "core", "show", "version", NULL },
1691 handle_version, "Display version info",
1692 version_help, NULL, &cli_show_version_deprecated },
1694 { { "!", NULL },
1695 handle_bang, "Execute a shell command",
1696 bang_help },
1698 #if !defined(LOW_MEMORY)
1699 { { "core", "show", "file", "version", NULL },
1700 handle_show_version_files, "List versions of files used to build Asterisk",
1701 show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
1703 { { "core", "show", "threads", NULL },
1704 handle_show_threads, "Show running threads",
1705 show_threads_help },
1707 { { "core", "show", "profile", NULL },
1708 handle_show_profile, "Display profiling info",
1709 NULL, NULL, &cli_show_profile_deprecated },
1711 { { "core", "clear", "profile", NULL },
1712 handle_show_profile, "Clear profiling info",
1713 NULL, NULL, &cli_clear_profile_deprecated },
1714 #endif /* ! LOW_MEMORY */
1717 static int ast_el_read_char(EditLine *el, char *cp)
1719 int num_read = 0;
1720 int lastpos = 0;
1721 struct pollfd fds[2];
1722 int res;
1723 int max;
1724 #define EL_BUF_SIZE 512
1725 char buf[EL_BUF_SIZE];
1727 for (;;) {
1728 max = 1;
1729 fds[0].fd = ast_consock;
1730 fds[0].events = POLLIN;
1731 if (!ast_opt_exec) {
1732 fds[1].fd = STDIN_FILENO;
1733 fds[1].events = POLLIN;
1734 max++;
1736 res = poll(fds, max, -1);
1737 if (res < 0) {
1738 if (errno == EINTR)
1739 continue;
1740 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1741 break;
1744 if (!ast_opt_exec && fds[1].revents) {
1745 num_read = read(STDIN_FILENO, cp, 1);
1746 if (num_read < 1) {
1747 break;
1748 } else
1749 return (num_read);
1751 if (fds[0].revents) {
1752 res = read(ast_consock, buf, sizeof(buf) - 1);
1753 /* if the remote side disappears exit */
1754 if (res < 1) {
1755 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1756 if (!ast_opt_reconnect) {
1757 quit_handler(0, 0, 0, 0);
1758 } else {
1759 int tries;
1760 int reconnects_per_second = 20;
1761 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1762 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1763 if (ast_tryconnect()) {
1764 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1765 printf(term_quit());
1766 WELCOME_MESSAGE;
1767 if (!ast_opt_mute)
1768 fdprint(ast_consock, "logger mute silent");
1769 else
1770 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
1771 break;
1772 } else {
1773 usleep(1000000 / reconnects_per_second);
1776 if (tries >= 30 * reconnects_per_second) {
1777 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1778 quit_handler(0, 0, 0, 0);
1783 buf[res] = '\0';
1785 if (!ast_opt_exec && !lastpos)
1786 write(STDOUT_FILENO, "\r", 1);
1787 write(STDOUT_FILENO, buf, res);
1788 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
1789 *cp = CC_REFRESH;
1790 return(1);
1791 } else {
1792 lastpos = 1;
1797 *cp = '\0';
1798 return (0);
1801 static char *cli_prompt(EditLine *el)
1803 static char prompt[200];
1804 char *pfmt;
1805 int color_used = 0;
1806 char term_code[20];
1808 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1809 char *t = pfmt, *p = prompt;
1810 memset(prompt, 0, sizeof(prompt));
1811 while (*t != '\0' && *p < sizeof(prompt)) {
1812 if (*t == '%') {
1813 char hostname[MAXHOSTNAMELEN]="";
1814 int i;
1815 time_t ts;
1816 struct tm tm;
1817 #ifdef linux
1818 FILE *LOADAVG;
1819 #endif
1820 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1822 t++;
1823 switch (*t) {
1824 case 'C': /* color */
1825 t++;
1826 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1827 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1828 t += i - 1;
1829 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1830 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1831 t += i - 1;
1834 /* If the color has been reset correctly, then there's no need to reset it later */
1835 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1836 color_used = 0;
1837 } else {
1838 color_used = 1;
1840 break;
1841 case 'd': /* date */
1842 memset(&tm, 0, sizeof(tm));
1843 time(&ts);
1844 if (ast_localtime(&ts, &tm, NULL)) {
1845 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1847 break;
1848 case 'h': /* hostname */
1849 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1850 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1851 } else {
1852 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1854 break;
1855 case 'H': /* short hostname */
1856 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1857 for (i = 0; i < sizeof(hostname); i++) {
1858 if (hostname[i] == '.') {
1859 hostname[i] = '\0';
1860 break;
1863 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1864 } else {
1865 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1867 break;
1868 #ifdef linux
1869 case 'l': /* load avg */
1870 t++;
1871 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1872 float avg1, avg2, avg3;
1873 int actproc, totproc, npid, which;
1874 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1875 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1876 if (sscanf(t, "%d", &which) == 1) {
1877 switch (which) {
1878 case 1:
1879 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1880 break;
1881 case 2:
1882 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1883 break;
1884 case 3:
1885 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1886 break;
1887 case 4:
1888 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1889 break;
1890 case 5:
1891 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1892 break;
1896 break;
1897 #endif
1898 case 's': /* Asterisk system name (from asterisk.conf) */
1899 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1900 break;
1901 case 't': /* time */
1902 memset(&tm, 0, sizeof(tm));
1903 time(&ts);
1904 if (ast_localtime(&ts, &tm, NULL)) {
1905 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1907 break;
1908 case '#': /* process console or remote? */
1909 if (!ast_opt_remote) {
1910 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1911 } else {
1912 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1914 break;
1915 case '%': /* literal % */
1916 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1917 break;
1918 case '\0': /* % is last character - prevent bug */
1919 t--;
1920 break;
1922 while (*p != '\0') {
1923 p++;
1925 t++;
1926 } else {
1927 *p = *t;
1928 p++;
1929 t++;
1932 if (color_used) {
1933 /* Force colors back to normal at end */
1934 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1935 if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
1936 ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
1937 } else {
1938 /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
1939 strncat(p, term_code, sizeof(term_code));
1942 } else if (remotehostname)
1943 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1944 else
1945 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1947 return(prompt);
1950 static char **ast_el_strtoarr(char *buf)
1952 char **match_list = NULL, *retstr;
1953 size_t match_list_len;
1954 int matches = 0;
1956 match_list_len = 1;
1957 while ( (retstr = strsep(&buf, " ")) != NULL) {
1959 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1960 break;
1961 if (matches + 1 >= match_list_len) {
1962 match_list_len <<= 1;
1963 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1964 /* TODO: Handle memory allocation failure */
1968 match_list[matches++] = strdup(retstr);
1971 if (!match_list)
1972 return (char **) NULL;
1974 if (matches >= match_list_len) {
1975 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1976 /* TODO: Handle memory allocation failure */
1980 match_list[matches] = (char *) NULL;
1982 return match_list;
1985 static int ast_el_sort_compare(const void *i1, const void *i2)
1987 char *s1, *s2;
1989 s1 = ((char **)i1)[0];
1990 s2 = ((char **)i2)[0];
1992 return strcasecmp(s1, s2);
1995 static int ast_cli_display_match_list(char **matches, int len, int max)
1997 int i, idx, limit, count;
1998 int screenwidth = 0;
1999 int numoutput = 0, numoutputline = 0;
2001 screenwidth = ast_get_termcols(STDOUT_FILENO);
2003 /* find out how many entries can be put on one line, with two spaces between strings */
2004 limit = screenwidth / (max + 2);
2005 if (limit == 0)
2006 limit = 1;
2008 /* how many lines of output */
2009 count = len / limit;
2010 if (count * limit < len)
2011 count++;
2013 idx = 1;
2015 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2017 for (; count > 0; count--) {
2018 numoutputline = 0;
2019 for (i=0; i < limit && matches[idx]; i++, idx++) {
2021 /* Don't print dupes */
2022 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2023 i--;
2024 free(matches[idx]);
2025 matches[idx] = NULL;
2026 continue;
2029 numoutput++;
2030 numoutputline++;
2031 fprintf(stdout, "%-*s ", max, matches[idx]);
2032 free(matches[idx]);
2033 matches[idx] = NULL;
2035 if (numoutputline > 0)
2036 fprintf(stdout, "\n");
2039 return numoutput;
2043 static char *cli_complete(EditLine *el, int ch)
2045 int len = 0;
2046 char *ptr;
2047 int nummatches = 0;
2048 char **matches;
2049 int retval = CC_ERROR;
2050 char buf[2048];
2051 int res;
2053 LineInfo *lf = (LineInfo *)el_line(el);
2055 *(char *)lf->cursor = '\0';
2056 ptr = (char *)lf->cursor;
2057 if (ptr) {
2058 while (ptr > lf->buffer) {
2059 if (isspace(*ptr)) {
2060 ptr++;
2061 break;
2063 ptr--;
2067 len = lf->cursor - ptr;
2069 if (ast_opt_remote) {
2070 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2071 fdprint(ast_consock, buf);
2072 res = read(ast_consock, buf, sizeof(buf));
2073 buf[res] = '\0';
2074 nummatches = atoi(buf);
2076 if (nummatches > 0) {
2077 char *mbuf;
2078 int mlen = 0, maxmbuf = 2048;
2079 /* Start with a 2048 byte buffer */
2080 if (!(mbuf = ast_malloc(maxmbuf)))
2081 return (char *)(CC_ERROR);
2082 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2083 fdprint(ast_consock, buf);
2084 res = 0;
2085 mbuf[0] = '\0';
2086 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2087 if (mlen + 1024 > maxmbuf) {
2088 /* Every step increment buffer 1024 bytes */
2089 maxmbuf += 1024;
2090 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2091 return (char *)(CC_ERROR);
2093 /* Only read 1024 bytes at a time */
2094 res = read(ast_consock, mbuf + mlen, 1024);
2095 if (res > 0)
2096 mlen += res;
2098 mbuf[mlen] = '\0';
2100 matches = ast_el_strtoarr(mbuf);
2101 free(mbuf);
2102 } else
2103 matches = (char **) NULL;
2104 } else {
2105 char **p, *oldbuf=NULL;
2106 nummatches = 0;
2107 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2108 for (p = matches; p && *p; p++) {
2109 if (!oldbuf || strcmp(*p,oldbuf))
2110 nummatches++;
2111 oldbuf = *p;
2115 if (matches) {
2116 int i;
2117 int matches_num, maxlen, match_len;
2119 if (matches[0][0] != '\0') {
2120 el_deletestr(el, (int) len);
2121 el_insertstr(el, matches[0]);
2122 retval = CC_REFRESH;
2125 if (nummatches == 1) {
2126 /* Found an exact match */
2127 el_insertstr(el, " ");
2128 retval = CC_REFRESH;
2129 } else {
2130 /* Must be more than one match */
2131 for (i=1, maxlen=0; matches[i]; i++) {
2132 match_len = strlen(matches[i]);
2133 if (match_len > maxlen)
2134 maxlen = match_len;
2136 matches_num = i - 1;
2137 if (matches_num >1) {
2138 fprintf(stdout, "\n");
2139 ast_cli_display_match_list(matches, nummatches, maxlen);
2140 retval = CC_REDISPLAY;
2141 } else {
2142 el_insertstr(el," ");
2143 retval = CC_REFRESH;
2146 for (i = 0; matches[i]; i++)
2147 free(matches[i]);
2148 free(matches);
2151 return (char *)(long)retval;
2154 static int ast_el_initialize(void)
2156 HistEvent ev;
2157 char *editor = getenv("AST_EDITOR");
2159 if (el != NULL)
2160 el_end(el);
2161 if (el_hist != NULL)
2162 history_end(el_hist);
2164 el = el_init("asterisk", stdin, stdout, stderr);
2165 el_set(el, EL_PROMPT, cli_prompt);
2167 el_set(el, EL_EDITMODE, 1);
2168 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2169 el_hist = history_init();
2170 if (!el || !el_hist)
2171 return -1;
2173 /* setup history with 100 entries */
2174 history(el_hist, &ev, H_SETSIZE, 100);
2176 el_set(el, EL_HIST, history, el_hist);
2178 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2179 /* Bind <tab> to command completion */
2180 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2181 /* Bind ? to command completion */
2182 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2183 /* Bind ^D to redisplay */
2184 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2186 return 0;
2189 static int ast_el_add_history(char *buf)
2191 HistEvent ev;
2193 if (el_hist == NULL || el == NULL)
2194 ast_el_initialize();
2195 if (strlen(buf) > 256)
2196 return 0;
2197 return (history(el_hist, &ev, H_ENTER, buf));
2200 static int ast_el_write_history(char *filename)
2202 HistEvent ev;
2204 if (el_hist == NULL || el == NULL)
2205 ast_el_initialize();
2207 return (history(el_hist, &ev, H_SAVE, filename));
2210 static int ast_el_read_history(char *filename)
2212 char buf[256];
2213 FILE *f;
2214 int ret = -1;
2216 if (el_hist == NULL || el == NULL)
2217 ast_el_initialize();
2219 if ((f = fopen(filename, "r")) == NULL)
2220 return ret;
2222 while (!feof(f)) {
2223 fgets(buf, sizeof(buf), f);
2224 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2225 continue;
2226 if (ast_all_zeros(buf))
2227 continue;
2228 if ((ret = ast_el_add_history(buf)) == -1)
2229 break;
2231 fclose(f);
2233 return ret;
2236 static void ast_remotecontrol(char * data)
2238 char buf[80];
2239 int res;
2240 char filename[80] = "";
2241 char *hostname;
2242 char *cpid;
2243 char *version;
2244 int pid;
2245 char tmp[80];
2246 char *stringp = NULL;
2248 char *ebuf;
2249 int num = 0;
2251 read(ast_consock, buf, sizeof(buf));
2252 if (data)
2253 write(ast_consock, data, strlen(data) + 1);
2254 stringp = buf;
2255 hostname = strsep(&stringp, "/");
2256 cpid = strsep(&stringp, "/");
2257 version = strsep(&stringp, "\n");
2258 if (!version)
2259 version = "<Version Unknown>";
2260 stringp = hostname;
2261 strsep(&stringp, ".");
2262 if (cpid)
2263 pid = atoi(cpid);
2264 else
2265 pid = -1;
2266 if (!data) {
2267 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2268 fdprint(ast_consock, tmp);
2269 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2270 fdprint(ast_consock, tmp);
2271 if (!ast_opt_mute)
2272 fdprint(ast_consock, "logger mute silent");
2273 else
2274 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2276 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2277 remotehostname = hostname;
2278 if (getenv("HOME"))
2279 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2280 if (el_hist == NULL || el == NULL)
2281 ast_el_initialize();
2283 el_set(el, EL_GETCFN, ast_el_read_char);
2285 if (!ast_strlen_zero(filename))
2286 ast_el_read_history(filename);
2288 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2289 char tempchar;
2290 struct pollfd fds;
2291 fds.fd = ast_consock;
2292 fds.events = POLLIN;
2293 fds.revents = 0;
2294 while (poll(&fds, 1, 100) > 0)
2295 ast_el_read_char(el, &tempchar);
2296 return;
2298 for (;;) {
2299 ebuf = (char *)el_gets(el, &num);
2301 if (!ebuf && write(1, "", 1) < 0)
2302 break;
2304 if (!ast_strlen_zero(ebuf)) {
2305 if (ebuf[strlen(ebuf)-1] == '\n')
2306 ebuf[strlen(ebuf)-1] = '\0';
2307 if (!remoteconsolehandler(ebuf)) {
2308 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2309 if (res < 1) {
2310 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2311 break;
2316 printf("\nDisconnected from Asterisk server\n");
2319 static int show_version(void)
2321 printf("Asterisk " ASTERISK_VERSION "\n");
2322 return 0;
2325 static int show_cli_help(void) {
2326 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008, Digium, Inc. and others.\n");
2327 printf("Usage: asterisk [OPTIONS]\n");
2328 printf("Valid Options:\n");
2329 printf(" -V Display version number and exit\n");
2330 printf(" -C <configfile> Use an alternate configuration file\n");
2331 printf(" -G <group> Run as a group other than the caller\n");
2332 printf(" -U <user> Run as a user other than the caller\n");
2333 printf(" -c Provide console CLI\n");
2334 printf(" -d Enable extra debugging\n");
2335 #if HAVE_WORKING_FORK
2336 printf(" -f Do not fork\n");
2337 printf(" -F Always fork\n");
2338 #endif
2339 printf(" -g Dump core in case of a crash\n");
2340 printf(" -h This help screen\n");
2341 printf(" -i Initialize crypto keys at startup\n");
2342 printf(" -I Enable internal timing if Zaptel timer is available\n");
2343 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2344 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2345 printf(" -m Mute debugging and console output on the console\n");
2346 printf(" -n Disable console colorization\n");
2347 printf(" -p Run as pseudo-realtime thread\n");
2348 printf(" -q Quiet mode (suppress output)\n");
2349 printf(" -r Connect to Asterisk on this machine\n");
2350 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2351 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2352 printf(" belong after they are done\n");
2353 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2354 printf(" of output to the CLI\n");
2355 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2356 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2357 printf("\n");
2358 return 0;
2361 static void ast_readconfig(void)
2363 struct ast_config *cfg;
2364 struct ast_variable *v;
2365 char *config = AST_CONFIG_FILE;
2367 if (ast_opt_override_config) {
2368 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2369 if (!cfg)
2370 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2371 } else {
2372 cfg = ast_config_load(config);
2375 /* init with buildtime config */
2376 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2377 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2378 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2379 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2380 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2381 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2382 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2383 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2384 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2385 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2386 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2387 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2388 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2390 /* no asterisk.conf? no problem, use buildtime config! */
2391 if (!cfg) {
2392 return;
2395 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2396 if (!strcasecmp(v->name, "astctlpermissions")) {
2397 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2398 } else if (!strcasecmp(v->name, "astctlowner")) {
2399 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2400 } else if (!strcasecmp(v->name, "astctlgroup")) {
2401 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2402 } else if (!strcasecmp(v->name, "astctl")) {
2403 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2407 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2408 if (!strcasecmp(v->name, "astetcdir")) {
2409 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2410 } else if (!strcasecmp(v->name, "astspooldir")) {
2411 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2412 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2413 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2414 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2415 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2416 } else if (!strcasecmp(v->name, "astdatadir")) {
2417 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2418 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2419 } else if (!strcasecmp(v->name, "astlogdir")) {
2420 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2421 } else if (!strcasecmp(v->name, "astagidir")) {
2422 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2423 } else if (!strcasecmp(v->name, "astrundir")) {
2424 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2425 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2426 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2427 } else if (!strcasecmp(v->name, "astmoddir")) {
2428 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2432 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2433 /* verbose level (-v at startup) */
2434 if (!strcasecmp(v->name, "verbose")) {
2435 option_verbose = atoi(v->value);
2436 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2437 } else if (!strcasecmp(v->name, "timestamp")) {
2438 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2439 /* whether or not to support #exec in config files */
2440 } else if (!strcasecmp(v->name, "execincludes")) {
2441 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2442 /* debug level (-d at startup) */
2443 } else if (!strcasecmp(v->name, "debug")) {
2444 option_debug = 0;
2445 if (sscanf(v->value, "%d", &option_debug) != 1) {
2446 option_debug = ast_true(v->value);
2448 #if HAVE_WORKING_FORK
2449 /* Disable forking (-f at startup) */
2450 } else if (!strcasecmp(v->name, "nofork")) {
2451 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2452 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2453 } else if (!strcasecmp(v->name, "alwaysfork")) {
2454 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2455 #endif
2456 /* Run quietly (-q at startup ) */
2457 } else if (!strcasecmp(v->name, "quiet")) {
2458 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2459 /* Run as console (-c at startup, implies nofork) */
2460 } else if (!strcasecmp(v->name, "console")) {
2461 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2462 /* Run with high priority if the O/S permits (-p at startup) */
2463 } else if (!strcasecmp(v->name, "highpriority")) {
2464 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2465 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2466 } else if (!strcasecmp(v->name, "initcrypto")) {
2467 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2468 /* Disable ANSI colors for console (-c at startup) */
2469 } else if (!strcasecmp(v->name, "nocolor")) {
2470 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2471 /* Disable some usage warnings for picky people :p */
2472 } else if (!strcasecmp(v->name, "dontwarn")) {
2473 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2474 /* Dump core in case of crash (-g) */
2475 } else if (!strcasecmp(v->name, "dumpcore")) {
2476 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2477 /* Cache recorded sound files to another directory during recording */
2478 } else if (!strcasecmp(v->name, "cache_record_files")) {
2479 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2480 /* Specify cache directory */
2481 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2482 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2483 /* Build transcode paths via SLINEAR, instead of directly */
2484 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2485 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2486 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2487 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2488 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2489 /* Enable internal timing */
2490 } else if (!strcasecmp(v->name, "internal_timing")) {
2491 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2492 } else if (!strcasecmp(v->name, "maxcalls")) {
2493 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2494 option_maxcalls = 0;
2496 } else if (!strcasecmp(v->name, "maxload")) {
2497 double test[1];
2499 if (getloadavg(test, 1) == -1) {
2500 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2501 option_maxload = 0.0;
2502 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2503 option_maxload = 0.0;
2505 /* What user to run as */
2506 } else if (!strcasecmp(v->name, "runuser")) {
2507 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2508 /* What group to run as */
2509 } else if (!strcasecmp(v->name, "rungroup")) {
2510 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2511 } else if (!strcasecmp(v->name, "systemname")) {
2512 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2513 } else if (!strcasecmp(v->name, "languageprefix")) {
2514 ast_language_is_prefix = ast_true(v->value);
2517 ast_config_destroy(cfg);
2520 static void *monitor_sig_flags(void *unused)
2522 for (;;) {
2523 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2524 int a;
2525 poll(&p, 1, -1);
2526 if (sig_flags.need_reload) {
2527 sig_flags.need_reload = 0;
2528 ast_module_reload(NULL);
2530 if (sig_flags.need_quit) {
2531 sig_flags.need_quit = 0;
2532 quit_handler(0, 0, 1, 0);
2534 read(sig_alert_pipe[0], &a, sizeof(a));
2537 return NULL;
2540 int main(int argc, char *argv[])
2542 int c;
2543 char filename[80] = "";
2544 char hostname[MAXHOSTNAMELEN] = "";
2545 char tmp[80];
2546 char * xarg = NULL;
2547 int x;
2548 FILE *f;
2549 sigset_t sigs;
2550 int num;
2551 int isroot = 1;
2552 char *buf;
2553 char *runuser = NULL, *rungroup = NULL;
2555 /* Remember original args for restart */
2556 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2557 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2558 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2560 for (x=0; x<argc; x++)
2561 _argv[x] = argv[x];
2562 _argv[x] = NULL;
2564 if (geteuid() != 0)
2565 isroot = 0;
2567 /* if the progname is rasterisk consider it a remote console */
2568 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2569 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2571 if (gethostname(hostname, sizeof(hostname)-1))
2572 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2573 ast_mainpid = getpid();
2574 ast_ulaw_init();
2575 ast_alaw_init();
2576 callerid_init();
2577 ast_builtins_init();
2578 ast_utils_init();
2579 tdd_init();
2581 if (getenv("HOME"))
2582 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2583 /* Check for options */
2584 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2585 switch (c) {
2586 #if HAVE_WORKING_FORK
2587 case 'F':
2588 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2589 break;
2590 case 'f':
2591 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2592 break;
2593 #endif
2594 case 'd':
2595 option_debug++;
2596 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2597 break;
2598 case 'c':
2599 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2600 break;
2601 case 'n':
2602 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2603 break;
2604 case 'r':
2605 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2606 break;
2607 case 'R':
2608 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2609 break;
2610 case 'p':
2611 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2612 break;
2613 case 'v':
2614 option_verbose++;
2615 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2616 break;
2617 case 'm':
2618 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2619 break;
2620 case 'M':
2621 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2622 option_maxcalls = 0;
2623 break;
2624 case 'L':
2625 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2626 option_maxload = 0.0;
2627 break;
2628 case 'q':
2629 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2630 break;
2631 case 't':
2632 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2633 break;
2634 case 'T':
2635 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2636 break;
2637 case 'x':
2638 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2639 xarg = ast_strdupa(optarg);
2640 break;
2641 case 'C':
2642 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2643 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2644 break;
2645 case 'I':
2646 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2647 break;
2648 case 'i':
2649 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2650 break;
2651 case 'g':
2652 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2653 break;
2654 case 'h':
2655 show_cli_help();
2656 exit(0);
2657 case 'V':
2658 show_version();
2659 exit(0);
2660 case 'U':
2661 runuser = ast_strdupa(optarg);
2662 break;
2663 case 'G':
2664 rungroup = ast_strdupa(optarg);
2665 break;
2666 case '?':
2667 exit(1);
2671 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2672 ast_register_verbose(console_verboser);
2673 WELCOME_MESSAGE;
2676 if (ast_opt_console && !option_verbose)
2677 ast_verbose("[ Booting...\n");
2679 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2680 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2681 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2684 /* For remote connections, change the name of the remote connection.
2685 * We do this for the benefit of init scripts (which need to know if/when
2686 * the main asterisk process has died yet). */
2687 if (ast_opt_remote) {
2688 strcpy(argv[0], "rasterisk");
2689 for (x = 1; x < argc; x++) {
2690 argv[x] = argv[0] + 10;
2694 if (ast_opt_console && !option_verbose)
2695 ast_verbose("[ Reading Master Configuration ]\n");
2696 ast_readconfig();
2698 if (ast_opt_dump_core) {
2699 struct rlimit l;
2700 memset(&l, 0, sizeof(l));
2701 l.rlim_cur = RLIM_INFINITY;
2702 l.rlim_max = RLIM_INFINITY;
2703 if (setrlimit(RLIMIT_CORE, &l)) {
2704 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2708 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2709 rungroup = ast_config_AST_RUN_GROUP;
2710 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2711 runuser = ast_config_AST_RUN_USER;
2713 #ifndef __CYGWIN__
2715 if (isroot)
2716 ast_set_priority(ast_opt_high_priority);
2718 if (isroot && rungroup) {
2719 struct group *gr;
2720 gr = getgrnam(rungroup);
2721 if (!gr) {
2722 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2723 exit(1);
2725 if (setgid(gr->gr_gid)) {
2726 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2727 exit(1);
2729 if (setgroups(0, NULL)) {
2730 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2731 exit(1);
2733 if (option_verbose)
2734 ast_verbose("Running as group '%s'\n", rungroup);
2737 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
2738 #ifdef HAVE_CAP
2739 int has_cap = 1;
2740 #endif /* HAVE_CAP */
2741 struct passwd *pw;
2742 pw = getpwnam(runuser);
2743 if (!pw) {
2744 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2745 exit(1);
2747 #ifdef HAVE_CAP
2748 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
2749 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
2750 has_cap = 0;
2752 #endif /* HAVE_CAP */
2753 if (!isroot && pw->pw_uid != geteuid()) {
2754 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
2755 exit(1);
2757 if (!rungroup) {
2758 if (setgid(pw->pw_gid)) {
2759 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2760 exit(1);
2762 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
2763 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2764 exit(1);
2767 if (setuid(pw->pw_uid)) {
2768 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2769 exit(1);
2771 if (option_verbose)
2772 ast_verbose("Running as user '%s'\n", runuser);
2773 #ifdef HAVE_CAP
2774 if (has_cap) {
2775 cap_t cap;
2777 cap = cap_from_text("cap_net_admin=ep");
2779 if (cap_set_proc(cap))
2780 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
2782 if (cap_free(cap))
2783 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
2785 #endif /* HAVE_CAP */
2788 #endif /* __CYGWIN__ */
2790 #ifdef linux
2791 if (geteuid() && ast_opt_dump_core) {
2792 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2793 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2796 #endif
2798 ast_term_init();
2799 printf(term_end());
2800 fflush(stdout);
2802 if (ast_opt_console && !option_verbose)
2803 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2804 /* custom config setup */
2805 register_config_cli();
2806 read_config_maps();
2808 if (ast_opt_console) {
2809 if (el_hist == NULL || el == NULL)
2810 ast_el_initialize();
2812 if (!ast_strlen_zero(filename))
2813 ast_el_read_history(filename);
2816 if (ast_tryconnect()) {
2817 /* One is already running */
2818 if (ast_opt_remote) {
2819 if (ast_opt_exec) {
2820 ast_remotecontrol(xarg);
2821 quit_handler(0, 0, 0, 0);
2822 exit(0);
2824 printf(term_quit());
2825 ast_remotecontrol(NULL);
2826 quit_handler(0, 0, 0, 0);
2827 exit(0);
2828 } else {
2829 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2830 printf(term_quit());
2831 exit(1);
2833 } else if (ast_opt_remote || ast_opt_exec) {
2834 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2835 printf(term_quit());
2836 exit(1);
2838 /* Blindly write pid file since we couldn't connect */
2839 unlink(ast_config_AST_PID);
2840 f = fopen(ast_config_AST_PID, "w");
2841 if (f) {
2842 fprintf(f, "%ld\n", (long)getpid());
2843 fclose(f);
2844 } else
2845 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2847 #if HAVE_WORKING_FORK
2848 if (ast_opt_always_fork || !ast_opt_no_fork) {
2849 #ifndef HAVE_SBIN_LAUNCHD
2850 daemon(1, 0);
2851 ast_mainpid = getpid();
2852 /* Blindly re-write pid file since we are forking */
2853 unlink(ast_config_AST_PID);
2854 f = fopen(ast_config_AST_PID, "w");
2855 if (f) {
2856 fprintf(f, "%ld\n", (long)ast_mainpid);
2857 fclose(f);
2858 } else
2859 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2860 #else
2861 ast_log(LOG_WARNING, "Mac OS X detected. Use '/sbin/launchd -d' to launch with the nofork option.\n");
2862 #endif
2864 #endif
2866 /* Test recursive mutex locking. */
2867 if (test_for_thread_safety())
2868 ast_verbose("Warning! Asterisk is not thread safe.\n");
2870 ast_makesocket();
2871 sigemptyset(&sigs);
2872 sigaddset(&sigs, SIGHUP);
2873 sigaddset(&sigs, SIGTERM);
2874 sigaddset(&sigs, SIGINT);
2875 sigaddset(&sigs, SIGPIPE);
2876 sigaddset(&sigs, SIGWINCH);
2877 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2878 signal(SIGURG, urg_handler);
2879 signal(SIGINT, __quit_handler);
2880 signal(SIGTERM, __quit_handler);
2881 signal(SIGHUP, hup_handler);
2882 signal(SIGCHLD, child_handler);
2883 signal(SIGPIPE, SIG_IGN);
2885 /* ensure that the random number generators are seeded with a different value every time
2886 Asterisk is started
2888 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2889 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2891 if (init_logger()) {
2892 printf(term_quit());
2893 exit(1);
2896 threadstorage_init();
2898 astobj2_init();
2900 ast_autoservice_init();
2902 if (load_modules(1)) {
2903 printf(term_quit());
2904 exit(1);
2907 if (dnsmgr_init()) {
2908 printf(term_quit());
2909 exit(1);
2912 ast_http_init();
2914 ast_channels_init();
2916 if (init_manager()) {
2917 printf(term_quit());
2918 exit(1);
2921 if (ast_cdr_engine_init()) {
2922 printf(term_quit());
2923 exit(1);
2926 if (ast_device_state_engine_init()) {
2927 printf(term_quit());
2928 exit(1);
2931 ast_rtp_init();
2933 ast_udptl_init();
2935 if (ast_image_init()) {
2936 printf(term_quit());
2937 exit(1);
2940 if (ast_file_init()) {
2941 printf(term_quit());
2942 exit(1);
2945 if (load_pbx()) {
2946 printf(term_quit());
2947 exit(1);
2950 if (init_framer()) {
2951 printf(term_quit());
2952 exit(1);
2955 if (astdb_init()) {
2956 printf(term_quit());
2957 exit(1);
2960 if (ast_enum_init()) {
2961 printf(term_quit());
2962 exit(1);
2965 if (load_modules(0)) {
2966 printf(term_quit());
2967 exit(1);
2970 dnsmgr_start_refresh();
2972 /* We might have the option of showing a console, but for now just
2973 do nothing... */
2974 if (ast_opt_console && !option_verbose)
2975 ast_verbose(" ]\n");
2976 if (option_verbose || ast_opt_console)
2977 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2978 if (ast_opt_no_fork)
2979 consolethread = pthread_self();
2981 if (pipe(sig_alert_pipe))
2982 sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
2984 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2985 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2987 #ifdef __AST_DEBUG_MALLOC
2988 __ast_mm_init();
2989 #endif
2991 time(&ast_startuptime);
2992 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
2994 if (ast_opt_console) {
2995 /* Console stuff now... */
2996 /* Register our quit function */
2997 char title[256];
2998 pthread_attr_t attr;
2999 pthread_t dont_care;
3001 pthread_attr_init(&attr);
3002 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3003 ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);
3004 pthread_attr_destroy(&attr);
3006 set_icon("Asterisk");
3007 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
3008 set_title(title);
3010 for (;;) {
3011 buf = (char *)el_gets(el, &num);
3013 if (!buf && write(1, "", 1) < 0)
3014 goto lostterm;
3016 if (buf) {
3017 if (buf[strlen(buf)-1] == '\n')
3018 buf[strlen(buf)-1] = '\0';
3020 consolehandler((char *)buf);
3021 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
3022 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
3023 /* Whoa, stdout disappeared from under us... Make /dev/null's */
3024 int fd;
3025 fd = open("/dev/null", O_RDWR);
3026 if (fd > -1) {
3027 dup2(fd, STDOUT_FILENO);
3028 dup2(fd, STDIN_FILENO);
3029 } else
3030 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
3031 break;
3036 monitor_sig_flags(NULL);
3038 lostterm:
3039 return 0;