Let's also include aclocal.m4
[asterisk-bristuff.git] / main / asterisk.c
blobcee50d6770a30443f396b025259b50c8f2aa7802
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 Licensing
29 * \arg \ref DevDoc
30 * \arg \ref ConfigFiles
32 * \section copyright Copyright and author
34 * Copyright (C) 1999 - 2008, Digium, Inc.
35 * Asterisk is a trademark registered by Digium, Inc.
37 * \author Mark Spencer <markster@digium.com>
38 * Also see \ref AstCREDITS
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.
47 /*! \file
48 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
49 of PBX core functions and CLI interface.
53 #include "asterisk.h"
55 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
57 #undef sched_setscheduler
58 #undef setpriority
59 #include <unistd.h>
60 #include <stdlib.h>
61 #include <sys/time.h>
62 #include <fcntl.h>
63 #include <stdio.h>
64 #include <signal.h>
65 #include <sched.h>
66 #include <sys/socket.h>
67 #include <sys/un.h>
68 #include <sys/wait.h>
69 #include <string.h>
70 #include <errno.h>
71 #include <ctype.h>
72 #include <sys/resource.h>
73 #include <grp.h>
74 #include <pwd.h>
75 #include <sys/stat.h>
77 #if defined(HAVE_ZAPTEL) || defined (HAVE_DAHDI)
78 #include <sys/ioctl.h>
79 #include "asterisk/dahdi_compat.h"
80 #endif
82 #ifdef linux
83 #include <sys/prctl.h>
84 #ifdef HAVE_CAP
85 #include <sys/capability.h>
86 #endif /* HAVE_CAP */
87 #endif /* linux */
88 #include <regex.h>
90 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
91 #include <netdb.h>
92 #if defined(SOLARIS)
93 int daemon(int, int); /* defined in libresolv of all places */
94 #endif
95 #endif
97 #include "asterisk/logger.h"
98 #include "asterisk/options.h"
99 #include "asterisk/cli.h"
100 #include "asterisk/channel.h"
101 #include "asterisk/ulaw.h"
102 #include "asterisk/alaw.h"
103 #include "asterisk/callerid.h"
104 #include "asterisk/image.h"
105 #include "asterisk/tdd.h"
106 #include "asterisk/term.h"
107 #include "asterisk/manager.h"
108 #include "asterisk/cdr.h"
109 #include "asterisk/pbx.h"
110 #include "asterisk/enum.h"
111 #include "asterisk/rtp.h"
112 #include "asterisk/http.h"
113 #include "asterisk/udptl.h"
114 #include "asterisk/app.h"
115 #include "asterisk/lock.h"
116 #include "asterisk/utils.h"
117 #include "asterisk/file.h"
118 #include "asterisk/io.h"
119 #include "asterisk/lock.h"
120 #include "editline/histedit.h"
121 #include "asterisk/config.h"
122 #include "asterisk/version.h"
123 #include "asterisk/linkedlists.h"
124 #include "asterisk/devicestate.h"
125 #include "asterisk/module.h"
127 #include "asterisk/doxyref.h" /* Doxygen documentation */
129 #include "../defaults.h"
131 #ifndef AF_LOCAL
132 #define AF_LOCAL AF_UNIX
133 #define PF_LOCAL PF_UNIX
134 #endif
136 #define AST_MAX_CONNECTS 128
137 #define NUM_MSGS 64
139 /*! \brief Welcome message when starting a CLI interface */
140 #define WELCOME_MESSAGE \
141 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008 Digium, Inc. and others.\n"); \
142 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
143 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
144 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
145 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
146 ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
147 ast_verbose("=========================================================================\n")
149 /*! \defgroup main_options Main Configuration Options
150 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
151 the operating system command line when starting Asterisk
152 Some of them can be changed in the CLI
154 /*! @{ */
156 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
158 int option_verbose; /*!< Verbosity level */
159 int option_debug; /*!< Debug level */
161 double option_maxload; /*!< Max load avg on system */
162 int option_maxcalls; /*!< Max number of active calls */
164 /*! @} */
166 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
167 char debug_filename[AST_FILENAME_MAX] = "";
168 #ifdef HAVE_ZAPTEL
169 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "Zap";
170 static size_t _dahdi_chan_name_len = 3;
171 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_ZAP_MODE;
172 #else
173 static char _dahdi_chan_name[AST_CHANNEL_NAME] = "DAHDI";
174 static size_t _dahdi_chan_name_len = 5;
175 static enum dahdi_chan_modes _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
176 #endif
177 const char *dahdi_chan_name;
178 const size_t *dahdi_chan_name_len;
179 const enum dahdi_chan_modes *dahdi_chan_mode;
181 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
182 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
183 pid_t ast_mainpid;
184 struct console {
185 int fd; /*!< File descriptor */
186 int p[2]; /*!< Pipe */
187 pthread_t t; /*!< Thread of handler */
188 int mute; /*!< Is the console muted for logs */
191 struct ast_atexit {
192 void (*func)(void);
193 AST_LIST_ENTRY(ast_atexit) list;
196 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
198 time_t ast_startuptime;
199 time_t ast_lastreloadtime;
201 static History *el_hist;
202 static EditLine *el;
203 static char *remotehostname;
205 struct console consoles[AST_MAX_CONNECTS];
207 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
209 static int ast_el_add_history(char *);
210 static int ast_el_read_history(char *);
211 static int ast_el_write_history(char *);
213 char ast_config_AST_CONFIG_DIR[PATH_MAX];
214 char ast_config_AST_CONFIG_FILE[PATH_MAX];
215 char ast_config_AST_MODULE_DIR[PATH_MAX];
216 char ast_config_AST_SPOOL_DIR[PATH_MAX];
217 char ast_config_AST_MONITOR_DIR[PATH_MAX];
218 char ast_config_AST_VAR_DIR[PATH_MAX];
219 char ast_config_AST_DATA_DIR[PATH_MAX];
220 char ast_config_AST_LOG_DIR[PATH_MAX];
221 char ast_config_AST_AGI_DIR[PATH_MAX];
222 char ast_config_AST_DB[PATH_MAX];
223 char ast_config_AST_KEY_DIR[PATH_MAX];
224 char ast_config_AST_PID[PATH_MAX];
225 char ast_config_AST_SOCKET[PATH_MAX];
226 char ast_config_AST_RUN_DIR[PATH_MAX];
227 char ast_config_AST_RUN_USER[PATH_MAX];
228 char ast_config_AST_RUN_GROUP[PATH_MAX];
229 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
230 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
231 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
232 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
233 char ast_config_AST_SYSTEM_NAME[20] = "";
235 extern const char *ast_build_hostname;
236 extern const char *ast_build_kernel;
237 extern const char *ast_build_machine;
238 extern const char *ast_build_os;
239 extern const char *ast_build_date;
240 extern const char *ast_build_user;
242 static char *_argv[256];
243 static int shuttingdown;
244 static int restartnow;
245 static pthread_t consolethread = AST_PTHREADT_NULL;
247 static char randompool[256];
249 static int sig_alert_pipe[2] = { -1, -1 };
250 static struct {
251 unsigned int need_reload:1;
252 unsigned int need_quit:1;
253 } sig_flags;
255 #if !defined(LOW_MEMORY)
256 struct file_version {
257 AST_LIST_ENTRY(file_version) list;
258 const char *file;
259 char *version;
262 static AST_LIST_HEAD_STATIC(file_versions, file_version);
264 void ast_register_file_version(const char *file, const char *version)
266 struct file_version *new;
267 char *work;
268 size_t version_length;
270 work = ast_strdupa(version);
271 work = ast_strip(ast_strip_quoted(work, "$", "$"));
272 version_length = strlen(work) + 1;
274 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
275 return;
277 new->file = file;
278 new->version = (char *) new + sizeof(*new);
279 memcpy(new->version, work, version_length);
280 AST_LIST_LOCK(&file_versions);
281 AST_LIST_INSERT_HEAD(&file_versions, new, list);
282 AST_LIST_UNLOCK(&file_versions);
285 void ast_unregister_file_version(const char *file)
287 struct file_version *find;
289 AST_LIST_LOCK(&file_versions);
290 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
291 if (!strcasecmp(find->file, file)) {
292 AST_LIST_REMOVE_CURRENT(&file_versions, list);
293 break;
296 AST_LIST_TRAVERSE_SAFE_END;
297 AST_LIST_UNLOCK(&file_versions);
298 if (find)
299 free(find);
302 struct thread_list_t {
303 AST_LIST_ENTRY(thread_list_t) list;
304 char *name;
305 pthread_t id;
308 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
310 static char show_threads_help[] =
311 "Usage: core show threads\n"
312 " List threads currently active in the system.\n";
314 void ast_register_thread(char *name)
316 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
318 if (!new)
319 return;
320 new->id = pthread_self();
321 new->name = name; /* steal the allocated memory for the thread name */
322 AST_LIST_LOCK(&thread_list);
323 AST_LIST_INSERT_HEAD(&thread_list, new, list);
324 AST_LIST_UNLOCK(&thread_list);
327 void ast_unregister_thread(void *id)
329 struct thread_list_t *x;
331 AST_LIST_LOCK(&thread_list);
332 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
333 if ((void *) x->id == id) {
334 AST_LIST_REMOVE_CURRENT(&thread_list, list);
335 break;
338 AST_LIST_TRAVERSE_SAFE_END;
339 AST_LIST_UNLOCK(&thread_list);
340 if (x) {
341 free(x->name);
342 free(x);
346 static int handle_show_threads(int fd, int argc, char *argv[])
348 int count = 0;
349 struct thread_list_t *cur;
351 AST_LIST_LOCK(&thread_list);
352 AST_LIST_TRAVERSE(&thread_list, cur, list) {
353 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
354 count++;
356 AST_LIST_UNLOCK(&thread_list);
357 ast_cli(fd, "%d threads listed.\n", count);
358 return 0;
361 struct profile_entry {
362 const char *name;
363 uint64_t scale; /* if non-zero, values are scaled by this */
364 int64_t mark;
365 int64_t value;
366 int64_t events;
369 struct profile_data {
370 int entries;
371 int max_size;
372 struct profile_entry e[0];
375 static struct profile_data *prof_data;
377 /*! \brief allocates a counter with a given name and scale.
378 * \return Returns the identifier of the counter.
380 int ast_add_profile(const char *name, uint64_t scale)
382 int l = sizeof(struct profile_data);
383 int n = 10; /* default entries */
385 if (prof_data == NULL) {
386 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
387 if (prof_data == NULL)
388 return -1;
389 prof_data->entries = 0;
390 prof_data->max_size = n;
392 if (prof_data->entries >= prof_data->max_size) {
393 void *p;
394 n = prof_data->max_size + 20;
395 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
396 if (p == NULL)
397 return -1;
398 prof_data = p;
399 prof_data->max_size = n;
401 n = prof_data->entries++;
402 prof_data->e[n].name = ast_strdup(name);
403 prof_data->e[n].value = 0;
404 prof_data->e[n].events = 0;
405 prof_data->e[n].mark = 0;
406 prof_data->e[n].scale = scale;
407 return n;
410 int64_t ast_profile(int i, int64_t delta)
412 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
413 return 0;
414 if (prof_data->e[i].scale > 1)
415 delta /= prof_data->e[i].scale;
416 prof_data->e[i].value += delta;
417 prof_data->e[i].events++;
418 return prof_data->e[i].value;
421 /* The RDTSC instruction was introduced on the Pentium processor and is not
422 * implemented on certain clones, like the Cyrix 586. Hence, the previous
423 * expectation of __i386__ was in error. */
424 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
425 #if defined(__FreeBSD__)
426 #include <machine/cpufunc.h>
427 #elif defined(linux)
428 static __inline uint64_t
429 rdtsc(void)
431 uint64_t rv;
433 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
434 return (rv);
436 #endif
437 #else /* supply a dummy function on other platforms */
438 static __inline uint64_t
439 rdtsc(void)
441 return 0;
443 #endif
445 int64_t ast_mark(int i, int startstop)
447 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
448 return 0;
449 if (startstop == 1)
450 prof_data->e[i].mark = rdtsc();
451 else {
452 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
453 if (prof_data->e[i].scale > 1)
454 prof_data->e[i].mark /= prof_data->e[i].scale;
455 prof_data->e[i].value += prof_data->e[i].mark;
456 prof_data->e[i].events++;
458 return prof_data->e[i].mark;
461 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
463 int i, min, max;
464 char *search = NULL;
466 if (prof_data == NULL)
467 return 0;
469 min = 0;
470 max = prof_data->entries;
471 if (argc >= 3) { /* specific entries */
472 if (isdigit(argv[2][0])) {
473 min = atoi(argv[2]);
474 if (argc == 4 && strcmp(argv[3], "-"))
475 max = atoi(argv[3]);
476 } else
477 search = argv[2];
479 if (max > prof_data->entries)
480 max = prof_data->entries;
481 if (!strcmp(argv[0], "clear")) {
482 for (i= min; i < max; i++) {
483 if (!search || strstr(prof_data->e[i].name, search)) {
484 prof_data->e[i].value = 0;
485 prof_data->e[i].events = 0;
488 return 0;
490 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
491 prof_data->entries, prof_data->max_size);
492 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
493 "Value", "Average", "Name");
494 for (i = min; i < max; i++) {
495 struct profile_entry *e = &prof_data->e[i];
496 if (!search || strstr(prof_data->e[i].name, search))
497 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
499 (long)e->scale,
500 (long)e->events, (long long)e->value,
501 (long long)(e->events ? e->value / e->events : e->value),
502 e->name);
504 return 0;
507 static int handle_show_profile(int fd, int argc, char *argv[])
509 int i, min, max;
510 char *search = NULL;
512 if (prof_data == NULL)
513 return 0;
515 min = 0;
516 max = prof_data->entries;
517 if (argc > 3) { /* specific entries */
518 if (isdigit(argv[3][0])) {
519 min = atoi(argv[3]);
520 if (argc == 5 && strcmp(argv[4], "-"))
521 max = atoi(argv[4]);
522 } else
523 search = argv[3];
525 if (max > prof_data->entries)
526 max = prof_data->entries;
527 if (!strcmp(argv[1], "clear")) {
528 for (i= min; i < max; i++) {
529 if (!search || strstr(prof_data->e[i].name, search)) {
530 prof_data->e[i].value = 0;
531 prof_data->e[i].events = 0;
534 return 0;
536 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
537 prof_data->entries, prof_data->max_size);
538 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
539 "Value", "Average", "Name");
540 for (i = min; i < max; i++) {
541 struct profile_entry *e = &prof_data->e[i];
542 if (!search || strstr(prof_data->e[i].name, search))
543 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
545 (long)e->scale,
546 (long)e->events, (long long)e->value,
547 (long long)(e->events ? e->value / e->events : e->value),
548 e->name);
550 return 0;
553 static char show_version_files_help[] =
554 "Usage: core show file version [like <pattern>]\n"
555 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
556 " Optional regular expression pattern is used to filter the file list.\n";
558 /*! \brief CLI command to list module versions */
559 static int handle_show_version_files_deprecated(int fd, int argc, char *argv[])
561 #define FORMAT "%-25.25s %-40.40s\n"
562 struct file_version *iterator;
563 regex_t regexbuf;
564 int havepattern = 0;
565 int havename = 0;
566 int count_files = 0;
568 switch (argc) {
569 case 5:
570 if (!strcasecmp(argv[3], "like")) {
571 if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
572 return RESULT_SHOWUSAGE;
573 havepattern = 1;
574 } else
575 return RESULT_SHOWUSAGE;
576 break;
577 case 4:
578 havename = 1;
579 break;
580 case 3:
581 break;
582 default:
583 return RESULT_SHOWUSAGE;
586 ast_cli(fd, FORMAT, "File", "Revision");
587 ast_cli(fd, FORMAT, "----", "--------");
588 AST_LIST_LOCK(&file_versions);
589 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
590 if (havename && strcasecmp(iterator->file, argv[3]))
591 continue;
593 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
594 continue;
596 ast_cli(fd, FORMAT, iterator->file, iterator->version);
597 count_files++;
598 if (havename)
599 break;
601 AST_LIST_UNLOCK(&file_versions);
602 if (!havename) {
603 ast_cli(fd, "%d files listed.\n", count_files);
606 if (havepattern)
607 regfree(&regexbuf);
609 return RESULT_SUCCESS;
610 #undef FORMAT
613 static int handle_show_version_files(int fd, int argc, char *argv[])
615 #define FORMAT "%-25.25s %-40.40s\n"
616 struct file_version *iterator;
617 regex_t regexbuf;
618 int havepattern = 0;
619 int havename = 0;
620 int count_files = 0;
622 switch (argc) {
623 case 6:
624 if (!strcasecmp(argv[4], "like")) {
625 if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
626 return RESULT_SHOWUSAGE;
627 havepattern = 1;
628 } else
629 return RESULT_SHOWUSAGE;
630 break;
631 case 5:
632 havename = 1;
633 break;
634 case 4:
635 break;
636 default:
637 return RESULT_SHOWUSAGE;
640 ast_cli(fd, FORMAT, "File", "Revision");
641 ast_cli(fd, FORMAT, "----", "--------");
642 AST_LIST_LOCK(&file_versions);
643 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
644 if (havename && strcasecmp(iterator->file, argv[4]))
645 continue;
647 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
648 continue;
650 ast_cli(fd, FORMAT, iterator->file, iterator->version);
651 count_files++;
652 if (havename)
653 break;
655 AST_LIST_UNLOCK(&file_versions);
656 if (!havename) {
657 ast_cli(fd, "%d files listed.\n", count_files);
660 if (havepattern)
661 regfree(&regexbuf);
663 return RESULT_SUCCESS;
664 #undef FORMAT
667 static char *complete_show_version_files_deprecated(const char *line, const char *word, int pos, int state)
669 struct file_version *find;
670 int which = 0;
671 char *ret = NULL;
672 int matchlen = strlen(word);
674 if (pos != 3)
675 return NULL;
677 AST_LIST_LOCK(&file_versions);
678 AST_LIST_TRAVERSE(&file_versions, find, list) {
679 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
680 ret = ast_strdup(find->file);
681 break;
684 AST_LIST_UNLOCK(&file_versions);
686 return ret;
689 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
691 struct file_version *find;
692 int which = 0;
693 char *ret = NULL;
694 int matchlen = strlen(word);
696 if (pos != 4)
697 return NULL;
699 AST_LIST_LOCK(&file_versions);
700 AST_LIST_TRAVERSE(&file_versions, find, list) {
701 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
702 ret = ast_strdup(find->file);
703 break;
706 AST_LIST_UNLOCK(&file_versions);
708 return ret;
711 #endif /* ! LOW_MEMORY */
713 int ast_register_atexit(void (*func)(void))
715 struct ast_atexit *ae;
717 if (!(ae = ast_calloc(1, sizeof(*ae))))
718 return -1;
720 ae->func = func;
722 ast_unregister_atexit(func);
724 AST_LIST_LOCK(&atexits);
725 AST_LIST_INSERT_HEAD(&atexits, ae, list);
726 AST_LIST_UNLOCK(&atexits);
728 return 0;
731 void ast_unregister_atexit(void (*func)(void))
733 struct ast_atexit *ae = NULL;
735 AST_LIST_LOCK(&atexits);
736 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
737 if (ae->func == func) {
738 AST_LIST_REMOVE_CURRENT(&atexits, list);
739 break;
742 AST_LIST_TRAVERSE_SAFE_END
743 AST_LIST_UNLOCK(&atexits);
745 if (ae)
746 free(ae);
749 /* Sending commands from consoles back to the daemon requires a terminating NULL */
750 static int fdsend(int fd, const char *s)
752 return write(fd, s, strlen(s) + 1);
755 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
756 static int fdprint(int fd, const char *s)
758 return write(fd, s, strlen(s));
761 /*! \brief NULL handler so we can collect the child exit status */
762 static void null_sig_handler(int signal)
767 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
768 /*! \brief Keep track of how many threads are currently trying to wait*() on
769 * a child process */
770 static unsigned int safe_system_level = 0;
771 static void *safe_system_prev_handler;
773 void ast_replace_sigchld(void)
775 unsigned int level;
777 ast_mutex_lock(&safe_system_lock);
778 level = safe_system_level++;
780 /* only replace the handler if it has not already been done */
781 if (level == 0)
782 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
784 ast_mutex_unlock(&safe_system_lock);
787 void ast_unreplace_sigchld(void)
789 unsigned int level;
791 ast_mutex_lock(&safe_system_lock);
792 level = --safe_system_level;
794 /* only restore the handler if we are the last one */
795 if (level == 0)
796 signal(SIGCHLD, safe_system_prev_handler);
798 ast_mutex_unlock(&safe_system_lock);
801 int ast_safe_system(const char *s)
803 pid_t pid;
804 #ifdef HAVE_WORKING_FORK
805 int x;
806 #endif
807 int res;
808 struct rusage rusage;
809 int status;
811 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
812 ast_replace_sigchld();
814 #ifdef HAVE_WORKING_FORK
815 pid = fork();
816 #else
817 pid = vfork();
818 #endif
820 if (pid == 0) {
821 #ifdef HAVE_WORKING_FORK
822 if (ast_opt_high_priority)
823 ast_set_priority(0);
824 /* Close file descriptors and launch system command */
825 for (x = STDERR_FILENO + 1; x < 4096; x++)
826 close(x);
827 #endif
828 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
829 _exit(1);
830 } else if (pid > 0) {
831 for(;;) {
832 res = wait4(pid, &status, 0, &rusage);
833 if (res > -1) {
834 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
835 break;
836 } else if (errno != EINTR)
837 break;
839 } else {
840 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
841 res = -1;
844 ast_unreplace_sigchld();
845 #else
846 res = -1;
847 #endif
849 return res;
853 * \brief mute or unmute a console from logging
855 void ast_console_toggle_mute(int fd, int silent) {
856 int x;
857 for (x = 0;x < AST_MAX_CONNECTS; x++) {
858 if (fd == consoles[x].fd) {
859 if (consoles[x].mute) {
860 consoles[x].mute = 0;
861 if (!silent)
862 ast_cli(fd, "Console is not muted anymore.\n");
863 } else {
864 consoles[x].mute = 1;
865 if (!silent)
866 ast_cli(fd, "Console is muted.\n");
868 return;
871 ast_cli(fd, "Couldn't find remote console.\n");
875 * \brief log the string to all attached console clients
877 static void ast_network_puts_mutable(const char *string)
879 int x;
880 for (x = 0;x < AST_MAX_CONNECTS; x++) {
881 if (consoles[x].mute)
882 continue;
883 if (consoles[x].fd > -1)
884 fdprint(consoles[x].p[1], string);
889 * \brief log the string to the console, and all attached
890 * console clients
892 void ast_console_puts_mutable(const char *string)
894 fputs(string, stdout);
895 fflush(stdout);
896 ast_network_puts_mutable(string);
900 * \brief write the string to all attached console clients
902 static void ast_network_puts(const char *string)
904 int x;
905 for (x=0; x < AST_MAX_CONNECTS; x++) {
906 if (consoles[x].fd > -1)
907 fdprint(consoles[x].p[1], string);
912 * write the string to the console, and all attached
913 * console clients
915 void ast_console_puts(const char *string)
917 fputs(string, stdout);
918 fflush(stdout);
919 ast_network_puts(string);
922 static void network_verboser(const char *s)
924 ast_network_puts_mutable(s);
927 static pthread_t lthread;
929 static void *netconsole(void *vconsole)
931 struct console *con = vconsole;
932 char hostname[MAXHOSTNAMELEN] = "";
933 char tmp[512];
934 int res;
935 struct pollfd fds[2];
937 if (gethostname(hostname, sizeof(hostname)-1))
938 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
939 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
940 fdprint(con->fd, tmp);
941 for(;;) {
942 fds[0].fd = con->fd;
943 fds[0].events = POLLIN;
944 fds[0].revents = 0;
945 fds[1].fd = con->p[0];
946 fds[1].events = POLLIN;
947 fds[1].revents = 0;
949 res = poll(fds, 2, -1);
950 if (res < 0) {
951 if (errno != EINTR)
952 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
953 continue;
955 if (fds[0].revents) {
956 res = read(con->fd, tmp, sizeof(tmp));
957 if (res < 1) {
958 break;
960 tmp[res] = 0;
961 ast_cli_command_multiple(con->fd, res, tmp);
963 if (fds[1].revents) {
964 res = read(con->p[0], tmp, sizeof(tmp));
965 if (res < 1) {
966 ast_log(LOG_ERROR, "read returned %d\n", res);
967 break;
969 res = write(con->fd, tmp, res);
970 if (res < 1)
971 break;
974 if (option_verbose > 2)
975 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
976 close(con->fd);
977 close(con->p[0]);
978 close(con->p[1]);
979 con->fd = -1;
981 return NULL;
984 static void *listener(void *unused)
986 struct sockaddr_un sunaddr;
987 int s;
988 socklen_t len;
989 int x;
990 int flags;
991 struct pollfd fds[1];
992 pthread_attr_t attr;
993 pthread_attr_init(&attr);
994 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
995 for (;;) {
996 if (ast_socket < 0)
997 return NULL;
998 fds[0].fd = ast_socket;
999 fds[0].events = POLLIN;
1000 s = poll(fds, 1, -1);
1001 pthread_testcancel();
1002 if (s < 0) {
1003 if (errno != EINTR)
1004 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1005 continue;
1007 len = sizeof(sunaddr);
1008 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1009 if (s < 0) {
1010 if (errno != EINTR)
1011 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1012 } else {
1013 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1014 if (consoles[x].fd < 0) {
1015 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1016 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1017 consoles[x].fd = -1;
1018 fdprint(s, "Server failed to create pipe\n");
1019 close(s);
1020 break;
1022 flags = fcntl(consoles[x].p[1], F_GETFL);
1023 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1024 consoles[x].fd = s;
1025 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1026 if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) {
1027 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1028 close(consoles[x].p[0]);
1029 close(consoles[x].p[1]);
1030 consoles[x].fd = -1;
1031 fdprint(s, "Server failed to spawn thread\n");
1032 close(s);
1034 break;
1037 if (x >= AST_MAX_CONNECTS) {
1038 fdprint(s, "No more connections allowed\n");
1039 ast_log(LOG_WARNING, "No more connections allowed\n");
1040 close(s);
1041 } else if (consoles[x].fd > -1) {
1042 if (option_verbose > 2)
1043 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
1047 return NULL;
1050 static int ast_makesocket(void)
1052 struct sockaddr_un sunaddr;
1053 int res;
1054 int x;
1055 uid_t uid = -1;
1056 gid_t gid = -1;
1058 for (x = 0; x < AST_MAX_CONNECTS; x++)
1059 consoles[x].fd = -1;
1060 unlink(ast_config_AST_SOCKET);
1061 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1062 if (ast_socket < 0) {
1063 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1064 return -1;
1066 memset(&sunaddr, 0, sizeof(sunaddr));
1067 sunaddr.sun_family = AF_LOCAL;
1068 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1069 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1070 if (res) {
1071 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1072 close(ast_socket);
1073 ast_socket = -1;
1074 return -1;
1076 res = listen(ast_socket, 2);
1077 if (res < 0) {
1078 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1079 close(ast_socket);
1080 ast_socket = -1;
1081 return -1;
1083 ast_register_verbose(network_verboser);
1084 ast_pthread_create_background(&lthread, NULL, listener, NULL);
1086 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1087 struct passwd *pw;
1088 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
1089 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1090 } else {
1091 uid = pw->pw_uid;
1095 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1096 struct group *grp;
1097 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
1098 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1099 } else {
1100 gid = grp->gr_gid;
1104 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1105 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1107 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1108 int p1;
1109 mode_t p;
1110 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
1111 p = p1;
1112 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1113 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1116 return 0;
1119 static int ast_tryconnect(void)
1121 struct sockaddr_un sunaddr;
1122 int res;
1123 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1124 if (ast_consock < 0) {
1125 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1126 return 0;
1128 memset(&sunaddr, 0, sizeof(sunaddr));
1129 sunaddr.sun_family = AF_LOCAL;
1130 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1131 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1132 if (res) {
1133 close(ast_consock);
1134 ast_consock = -1;
1135 return 0;
1136 } else
1137 return 1;
1140 /*! \brief Urgent handler
1142 Called by soft_hangup to interrupt the poll, read, or other
1143 system call. We don't actually need to do anything though.
1144 Remember: Cannot EVER ast_log from within a signal handler
1146 static void urg_handler(int num)
1148 signal(num, urg_handler);
1149 return;
1152 static void hup_handler(int num)
1154 int a = 0;
1155 if (option_verbose > 1)
1156 printf("Received HUP signal -- Reloading configs\n");
1157 if (restartnow)
1158 execvp(_argv[0], _argv);
1159 sig_flags.need_reload = 1;
1160 if (sig_alert_pipe[1] != -1)
1161 write(sig_alert_pipe[1], &a, sizeof(a));
1162 signal(num, hup_handler);
1165 static void child_handler(int sig)
1167 /* Must not ever ast_log or ast_verbose within signal handler */
1168 int n, status;
1171 * Reap all dead children -- not just one
1173 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1175 if (n == 0 && option_debug)
1176 printf("Huh? Child handler, but nobody there?\n");
1177 signal(sig, child_handler);
1180 /*! \brief Set an X-term or screen title */
1181 static void set_title(char *text)
1183 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1184 fprintf(stdout, "\033]2;%s\007", text);
1187 static void set_icon(char *text)
1189 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1190 fprintf(stdout, "\033]1;%s\007", text);
1193 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1194 else. If your PBX has heavy activity on it, this is a good thing. */
1195 int ast_set_priority(int pri)
1197 struct sched_param sched;
1198 memset(&sched, 0, sizeof(sched));
1199 #ifdef __linux__
1200 if (pri) {
1201 sched.sched_priority = 10;
1202 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1203 ast_log(LOG_WARNING, "Unable to set high priority\n");
1204 return -1;
1205 } else
1206 if (option_verbose)
1207 ast_verbose("Set to realtime thread\n");
1208 } else {
1209 sched.sched_priority = 0;
1210 /* According to the manpage, these parameters can never fail. */
1211 sched_setscheduler(0, SCHED_OTHER, &sched);
1213 #else
1214 if (pri) {
1215 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1216 ast_log(LOG_WARNING, "Unable to set high priority\n");
1217 return -1;
1218 } else
1219 if (option_verbose)
1220 ast_verbose("Set to high priority\n");
1221 } else {
1222 /* According to the manpage, these parameters can never fail. */
1223 setpriority(PRIO_PROCESS, 0, 0);
1225 #endif
1226 return 0;
1229 static void ast_run_atexits(void)
1231 struct ast_atexit *ae;
1232 AST_LIST_LOCK(&atexits);
1233 AST_LIST_TRAVERSE(&atexits, ae, list) {
1234 if (ae->func)
1235 ae->func();
1237 AST_LIST_UNLOCK(&atexits);
1240 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1242 char filename[80] = "";
1243 time_t s,e;
1244 int x;
1245 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1246 ast_cdr_engine_term();
1247 if (safeshutdown) {
1248 shuttingdown = 1;
1249 if (!nice) {
1250 /* Begin shutdown routine, hanging up active channels */
1251 ast_begin_shutdown(1);
1252 if (option_verbose && ast_opt_console)
1253 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1254 time(&s);
1255 for (;;) {
1256 time(&e);
1257 /* Wait up to 15 seconds for all channels to go away */
1258 if ((e - s) > 15)
1259 break;
1260 if (!ast_active_channels())
1261 break;
1262 if (!shuttingdown)
1263 break;
1264 /* Sleep 1/10 of a second */
1265 usleep(100000);
1267 } else {
1268 if (nice < 2)
1269 ast_begin_shutdown(0);
1270 if (option_verbose && ast_opt_console)
1271 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1272 for (;;) {
1273 if (!ast_active_channels())
1274 break;
1275 if (!shuttingdown)
1276 break;
1277 sleep(1);
1281 if (!shuttingdown) {
1282 if (option_verbose && ast_opt_console)
1283 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1284 return;
1287 if (nice)
1288 ast_module_shutdown();
1290 if (ast_opt_console || ast_opt_remote) {
1291 if (getenv("HOME"))
1292 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1293 if (!ast_strlen_zero(filename))
1294 ast_el_write_history(filename);
1295 if (el != NULL)
1296 el_end(el);
1297 if (el_hist != NULL)
1298 history_end(el_hist);
1300 if (option_verbose)
1301 ast_verbose("Executing last minute cleanups\n");
1302 ast_run_atexits();
1303 /* Called on exit */
1304 if (option_verbose && ast_opt_console)
1305 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1306 if (option_debug)
1307 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1308 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1309 if (ast_socket > -1) {
1310 pthread_cancel(lthread);
1311 close(ast_socket);
1312 ast_socket = -1;
1313 unlink(ast_config_AST_SOCKET);
1315 if (ast_consock > -1)
1316 close(ast_consock);
1317 if (!ast_opt_remote)
1318 unlink(ast_config_AST_PID);
1319 printf(term_quit());
1320 if (restart) {
1321 if (option_verbose || ast_opt_console)
1322 ast_verbose("Preparing for Asterisk restart...\n");
1323 /* Mark all FD's for closing on exec */
1324 for (x=3; x < 32768; x++) {
1325 fcntl(x, F_SETFD, FD_CLOEXEC);
1327 if (option_verbose || ast_opt_console)
1328 ast_verbose("Asterisk is now restarting...\n");
1329 restartnow = 1;
1331 /* close logger */
1332 close_logger();
1334 /* If there is a consolethread running send it a SIGHUP
1335 so it can execvp, otherwise we can do it ourselves */
1336 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1337 pthread_kill(consolethread, SIGHUP);
1338 /* Give the signal handler some time to complete */
1339 sleep(2);
1340 } else
1341 execvp(_argv[0], _argv);
1343 } else {
1344 /* close logger */
1345 close_logger();
1347 exit(0);
1350 static void __quit_handler(int num)
1352 int a = 0;
1353 sig_flags.need_quit = 1;
1354 if (sig_alert_pipe[1] != -1)
1355 write(sig_alert_pipe[1], &a, sizeof(a));
1356 /* There is no need to restore the signal handler here, since the app
1357 * is going to exit */
1360 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1362 const char *c;
1364 /* Check for verboser preamble */
1365 if (*s == 127) {
1366 s++;
1369 if (!strncmp(s, cmp, strlen(cmp))) {
1370 c = s + strlen(cmp);
1371 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1372 return c;
1374 return NULL;
1377 static void console_verboser(const char *s)
1379 char tmp[80];
1380 const char *c = NULL;
1382 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1383 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1384 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1385 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1386 fputs(tmp, stdout);
1387 fputs(c, stdout);
1388 } else {
1389 if (*s == 127) {
1390 s++;
1392 fputs(s, stdout);
1395 fflush(stdout);
1397 /* Wake up a poll()ing console */
1398 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1399 pthread_kill(consolethread, SIGURG);
1402 static int ast_all_zeros(char *s)
1404 while (*s) {
1405 if (*s > 32)
1406 return 0;
1407 s++;
1409 return 1;
1412 static void consolehandler(char *s)
1414 printf(term_end());
1415 fflush(stdout);
1417 /* Called when readline data is available */
1418 if (!ast_all_zeros(s))
1419 ast_el_add_history(s);
1420 /* The real handler for bang */
1421 if (s[0] == '!') {
1422 if (s[1])
1423 ast_safe_system(s+1);
1424 else
1425 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1426 } else
1427 ast_cli_command(STDOUT_FILENO, s);
1430 static int remoteconsolehandler(char *s)
1432 int ret = 0;
1434 /* Called when readline data is available */
1435 if (!ast_all_zeros(s))
1436 ast_el_add_history(s);
1437 /* The real handler for bang */
1438 if (s[0] == '!') {
1439 if (s[1])
1440 ast_safe_system(s+1);
1441 else
1442 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1443 ret = 1;
1445 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1446 (s[4] == '\0' || isspace(s[4]))) {
1447 quit_handler(0, 0, 0, 0);
1448 ret = 1;
1451 return ret;
1454 static char abort_halt_help[] =
1455 "Usage: abort shutdown\n"
1456 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1457 " call operations.\n";
1459 static char shutdown_now_help[] =
1460 "Usage: stop now\n"
1461 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1463 static char shutdown_gracefully_help[] =
1464 "Usage: stop gracefully\n"
1465 " Causes Asterisk to not accept new calls, and exit when all\n"
1466 " active calls have terminated normally.\n";
1468 static char shutdown_when_convenient_help[] =
1469 "Usage: stop when convenient\n"
1470 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1472 static char restart_now_help[] =
1473 "Usage: restart now\n"
1474 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1475 " restart.\n";
1477 static char restart_gracefully_help[] =
1478 "Usage: restart gracefully\n"
1479 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1480 " restart when all active calls have ended.\n";
1482 static char restart_when_convenient_help[] =
1483 "Usage: restart when convenient\n"
1484 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1486 static char bang_help[] =
1487 "Usage: !<command>\n"
1488 " Executes a given shell command\n";
1490 static char show_warranty_help[] =
1491 "Usage: core show warranty\n"
1492 " Shows the warranty (if any) for this copy of Asterisk.\n";
1494 static char show_license_help[] =
1495 "Usage: core show license\n"
1496 " Shows the license(s) for this copy of Asterisk.\n";
1498 static char version_help[] =
1499 "Usage: core show version\n"
1500 " Shows Asterisk version information.\n";
1502 static int handle_version_deprecated(int fd, int argc, char *argv[])
1504 if (argc != 2)
1505 return RESULT_SHOWUSAGE;
1506 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1507 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1508 ast_build_machine, ast_build_os, ast_build_date);
1509 return RESULT_SUCCESS;
1512 static int handle_version(int fd, int argc, char *argv[])
1514 if (argc != 3)
1515 return RESULT_SHOWUSAGE;
1516 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1517 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1518 ast_build_machine, ast_build_os, ast_build_date);
1519 return RESULT_SUCCESS;
1522 #if 0
1523 static int handle_quit(int fd, int argc, char *argv[])
1525 if (argc != 1)
1526 return RESULT_SHOWUSAGE;
1527 quit_handler(0, 0, 1, 0);
1528 return RESULT_SUCCESS;
1530 #endif
1532 static int handle_shutdown_now(int fd, int argc, char *argv[])
1534 if (argc != 2)
1535 return RESULT_SHOWUSAGE;
1536 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1537 return RESULT_SUCCESS;
1540 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1542 if (argc != 2)
1543 return RESULT_SHOWUSAGE;
1544 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1545 return RESULT_SUCCESS;
1548 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1550 if (argc != 3)
1551 return RESULT_SHOWUSAGE;
1552 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1553 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1554 return RESULT_SUCCESS;
1557 static int handle_restart_now(int fd, int argc, char *argv[])
1559 if (argc != 2)
1560 return RESULT_SHOWUSAGE;
1561 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1562 return RESULT_SUCCESS;
1565 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1567 if (argc != 2)
1568 return RESULT_SHOWUSAGE;
1569 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1570 return RESULT_SUCCESS;
1573 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1575 if (argc != 3)
1576 return RESULT_SHOWUSAGE;
1577 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1578 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1579 return RESULT_SUCCESS;
1582 static int handle_abort_halt(int fd, int argc, char *argv[])
1584 if (argc != 2)
1585 return RESULT_SHOWUSAGE;
1586 ast_cancel_shutdown();
1587 shuttingdown = 0;
1588 return RESULT_SUCCESS;
1591 static int handle_bang(int fd, int argc, char *argv[])
1593 return RESULT_SUCCESS;
1595 static const char *warranty_lines[] = {
1596 "\n",
1597 " NO WARRANTY\n",
1598 "\n",
1599 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1600 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1601 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1602 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1603 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1604 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1605 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1606 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1607 "REPAIR OR CORRECTION.\n",
1608 "\n",
1609 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1610 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1611 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1612 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1613 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1614 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1615 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1616 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1617 "POSSIBILITY OF SUCH DAMAGES.\n",
1620 static int show_warranty(int fd, int argc, char *argv[])
1622 int x;
1624 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1625 ast_cli(fd, (char *) warranty_lines[x]);
1627 return RESULT_SUCCESS;
1630 static const char *license_lines[] = {
1631 "\n",
1632 "This program is free software; you can redistribute it and/or modify\n",
1633 "it under the terms of the GNU General Public License version 2 as\n",
1634 "published by the Free Software Foundation.\n",
1635 "\n",
1636 "This program also contains components licensed under other licenses.\n",
1637 "They include:\n",
1638 "\n",
1639 "This program is distributed in the hope that it will be useful,\n",
1640 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1641 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1642 "GNU General Public License for more details.\n",
1643 "\n",
1644 "You should have received a copy of the GNU General Public License\n",
1645 "along with this program; if not, write to the Free Software\n",
1646 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1649 static int show_license(int fd, int argc, char *argv[])
1651 int x;
1653 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1654 ast_cli(fd, (char *) license_lines[x]);
1656 return RESULT_SUCCESS;
1659 #define ASTERISK_PROMPT "*CLI> "
1661 #define ASTERISK_PROMPT2 "%s*CLI> "
1663 static struct ast_cli_entry cli_show_version_deprecated = {
1664 { "show", "version", NULL },
1665 handle_version_deprecated, "Display version info",
1666 version_help };
1668 #if !defined(LOW_MEMORY)
1669 static struct ast_cli_entry cli_show_version_files_deprecated = {
1670 { "show", "version", "files", NULL },
1671 handle_show_version_files_deprecated, NULL,
1672 NULL, complete_show_version_files_deprecated };
1674 static struct ast_cli_entry cli_show_profile_deprecated = {
1675 { "show", "profile", NULL },
1676 handle_show_profile_deprecated, NULL,
1677 NULL };
1679 static struct ast_cli_entry cli_clear_profile_deprecated = {
1680 { "clear", "profile", NULL },
1681 handle_show_profile_deprecated, NULL,
1682 NULL };
1683 #endif /* ! LOW_MEMORY */
1685 static struct ast_cli_entry cli_asterisk[] = {
1686 { { "abort", "halt", NULL },
1687 handle_abort_halt, "Cancel a running halt",
1688 abort_halt_help },
1690 { { "stop", "now", NULL },
1691 handle_shutdown_now, "Shut down Asterisk immediately",
1692 shutdown_now_help },
1694 { { "stop", "gracefully", NULL },
1695 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1696 shutdown_gracefully_help },
1698 { { "stop", "when", "convenient", NULL },
1699 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1700 shutdown_when_convenient_help },
1702 { { "restart", "now", NULL },
1703 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1705 { { "restart", "gracefully", NULL },
1706 handle_restart_gracefully, "Restart Asterisk gracefully",
1707 restart_gracefully_help },
1709 { { "restart", "when", "convenient", NULL },
1710 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1711 restart_when_convenient_help },
1713 { { "core", "show", "warranty", NULL },
1714 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1715 show_warranty_help },
1717 { { "core", "show", "license", NULL },
1718 show_license, "Show the license(s) for this copy of Asterisk",
1719 show_license_help },
1721 { { "core", "show", "version", NULL },
1722 handle_version, "Display version info",
1723 version_help, NULL, &cli_show_version_deprecated },
1725 { { "!", NULL },
1726 handle_bang, "Execute a shell command",
1727 bang_help },
1729 #if !defined(LOW_MEMORY)
1730 { { "core", "show", "file", "version", NULL },
1731 handle_show_version_files, "List versions of files used to build Asterisk",
1732 show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
1734 { { "core", "show", "threads", NULL },
1735 handle_show_threads, "Show running threads",
1736 show_threads_help },
1738 { { "core", "show", "profile", NULL },
1739 handle_show_profile, "Display profiling info",
1740 NULL, NULL, &cli_show_profile_deprecated },
1742 { { "core", "clear", "profile", NULL },
1743 handle_show_profile, "Clear profiling info",
1744 NULL, NULL, &cli_clear_profile_deprecated },
1745 #endif /* ! LOW_MEMORY */
1748 static int ast_el_read_char(EditLine *el, char *cp)
1750 int num_read = 0;
1751 int lastpos = 0;
1752 struct pollfd fds[2];
1753 int res;
1754 int max;
1755 #define EL_BUF_SIZE 512
1756 char buf[EL_BUF_SIZE];
1758 for (;;) {
1759 max = 1;
1760 fds[0].fd = ast_consock;
1761 fds[0].events = POLLIN;
1762 if (!ast_opt_exec) {
1763 fds[1].fd = STDIN_FILENO;
1764 fds[1].events = POLLIN;
1765 max++;
1767 res = poll(fds, max, -1);
1768 if (res < 0) {
1769 if (errno == EINTR)
1770 continue;
1771 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1772 break;
1775 if (!ast_opt_exec && fds[1].revents) {
1776 num_read = read(STDIN_FILENO, cp, 1);
1777 if (num_read < 1) {
1778 break;
1779 } else
1780 return (num_read);
1782 if (fds[0].revents) {
1783 char *tmp;
1784 res = read(ast_consock, buf, sizeof(buf) - 1);
1785 /* if the remote side disappears exit */
1786 if (res < 1) {
1787 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1788 if (!ast_opt_reconnect) {
1789 quit_handler(0, 0, 0, 0);
1790 } else {
1791 int tries;
1792 int reconnects_per_second = 20;
1793 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1794 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1795 if (ast_tryconnect()) {
1796 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1797 printf(term_quit());
1798 WELCOME_MESSAGE;
1799 if (!ast_opt_mute)
1800 fdsend(ast_consock, "logger mute silent");
1801 else
1802 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
1803 break;
1804 } else {
1805 usleep(1000000 / reconnects_per_second);
1808 if (tries >= 30 * reconnects_per_second) {
1809 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1810 quit_handler(0, 0, 0, 0);
1815 buf[res] = '\0';
1817 /* Strip preamble from asynchronous events, too */
1818 for (tmp = buf; *tmp; tmp++) {
1819 if (*tmp == 127) {
1820 memmove(tmp, tmp + 1, strlen(tmp));
1821 tmp--;
1825 /* Write over the CLI prompt */
1826 if (!ast_opt_exec && !lastpos)
1827 write(STDOUT_FILENO, "\r", 1);
1828 write(STDOUT_FILENO, buf, res);
1829 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
1830 *cp = CC_REFRESH;
1831 return(1);
1832 } else {
1833 lastpos = 1;
1838 *cp = '\0';
1839 return (0);
1842 static char *cli_prompt(EditLine *el)
1844 static char prompt[200];
1845 char *pfmt;
1846 int color_used = 0;
1847 char term_code[20];
1849 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1850 char *t = pfmt, *p = prompt;
1851 memset(prompt, 0, sizeof(prompt));
1852 while (*t != '\0' && *p < sizeof(prompt)) {
1853 if (*t == '%') {
1854 char hostname[MAXHOSTNAMELEN]="";
1855 int i;
1856 time_t ts;
1857 struct tm tm;
1858 #ifdef linux
1859 FILE *LOADAVG;
1860 #endif
1861 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1863 t++;
1864 switch (*t) {
1865 case 'C': /* color */
1866 t++;
1867 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1868 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1869 t += i - 1;
1870 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1871 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1872 t += i - 1;
1875 /* If the color has been reset correctly, then there's no need to reset it later */
1876 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1877 color_used = 0;
1878 } else {
1879 color_used = 1;
1881 break;
1882 case 'd': /* date */
1883 memset(&tm, 0, sizeof(tm));
1884 time(&ts);
1885 if (ast_localtime(&ts, &tm, NULL)) {
1886 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1888 break;
1889 case 'h': /* hostname */
1890 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1891 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1892 } else {
1893 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1895 break;
1896 case 'H': /* short hostname */
1897 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1898 for (i = 0; i < sizeof(hostname); i++) {
1899 if (hostname[i] == '.') {
1900 hostname[i] = '\0';
1901 break;
1904 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1905 } else {
1906 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1908 break;
1909 #ifdef linux
1910 case 'l': /* load avg */
1911 t++;
1912 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1913 float avg1, avg2, avg3;
1914 int actproc, totproc, npid, which;
1915 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1916 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1917 if (sscanf(t, "%d", &which) == 1) {
1918 switch (which) {
1919 case 1:
1920 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1921 break;
1922 case 2:
1923 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1924 break;
1925 case 3:
1926 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1927 break;
1928 case 4:
1929 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1930 break;
1931 case 5:
1932 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1933 break;
1937 break;
1938 #endif
1939 case 's': /* Asterisk system name (from asterisk.conf) */
1940 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1941 break;
1942 case 't': /* time */
1943 memset(&tm, 0, sizeof(tm));
1944 time(&ts);
1945 if (ast_localtime(&ts, &tm, NULL)) {
1946 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1948 break;
1949 case '#': /* process console or remote? */
1950 if (!ast_opt_remote) {
1951 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1952 } else {
1953 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1955 break;
1956 case '%': /* literal % */
1957 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1958 break;
1959 case '\0': /* % is last character - prevent bug */
1960 t--;
1961 break;
1963 while (*p != '\0') {
1964 p++;
1966 t++;
1967 } else {
1968 *p = *t;
1969 p++;
1970 t++;
1973 if (color_used) {
1974 /* Force colors back to normal at end */
1975 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1976 if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
1977 ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
1978 } else {
1979 /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
1980 strncat(p, term_code, sizeof(term_code));
1983 } else if (remotehostname)
1984 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1985 else
1986 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1988 return(prompt);
1991 static char **ast_el_strtoarr(char *buf)
1993 char **match_list = NULL, *retstr;
1994 size_t match_list_len;
1995 int matches = 0;
1997 match_list_len = 1;
1998 while ( (retstr = strsep(&buf, " ")) != NULL) {
2000 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2001 break;
2002 if (matches + 1 >= match_list_len) {
2003 match_list_len <<= 1;
2004 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2005 /* TODO: Handle memory allocation failure */
2009 match_list[matches++] = strdup(retstr);
2012 if (!match_list)
2013 return (char **) NULL;
2015 if (matches >= match_list_len) {
2016 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2017 /* TODO: Handle memory allocation failure */
2021 match_list[matches] = (char *) NULL;
2023 return match_list;
2026 static int ast_el_sort_compare(const void *i1, const void *i2)
2028 char *s1, *s2;
2030 s1 = ((char **)i1)[0];
2031 s2 = ((char **)i2)[0];
2033 return strcasecmp(s1, s2);
2036 static int ast_cli_display_match_list(char **matches, int len, int max)
2038 int i, idx, limit, count;
2039 int screenwidth = 0;
2040 int numoutput = 0, numoutputline = 0;
2042 screenwidth = ast_get_termcols(STDOUT_FILENO);
2044 /* find out how many entries can be put on one line, with two spaces between strings */
2045 limit = screenwidth / (max + 2);
2046 if (limit == 0)
2047 limit = 1;
2049 /* how many lines of output */
2050 count = len / limit;
2051 if (count * limit < len)
2052 count++;
2054 idx = 1;
2056 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2058 for (; count > 0; count--) {
2059 numoutputline = 0;
2060 for (i=0; i < limit && matches[idx]; i++, idx++) {
2062 /* Don't print dupes */
2063 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2064 i--;
2065 free(matches[idx]);
2066 matches[idx] = NULL;
2067 continue;
2070 numoutput++;
2071 numoutputline++;
2072 fprintf(stdout, "%-*s ", max, matches[idx]);
2073 free(matches[idx]);
2074 matches[idx] = NULL;
2076 if (numoutputline > 0)
2077 fprintf(stdout, "\n");
2080 return numoutput;
2084 static char *cli_complete(EditLine *el, int ch)
2086 int len = 0;
2087 char *ptr;
2088 int nummatches = 0;
2089 char **matches;
2090 int retval = CC_ERROR;
2091 char buf[2048];
2092 int res;
2094 LineInfo *lf = (LineInfo *)el_line(el);
2096 *(char *)lf->cursor = '\0';
2097 ptr = (char *)lf->cursor;
2098 if (ptr) {
2099 while (ptr > lf->buffer) {
2100 if (isspace(*ptr)) {
2101 ptr++;
2102 break;
2104 ptr--;
2108 len = lf->cursor - ptr;
2110 if (ast_opt_remote) {
2111 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2112 fdsend(ast_consock, buf);
2113 res = read(ast_consock, buf, sizeof(buf));
2114 buf[res] = '\0';
2115 nummatches = atoi(buf);
2117 if (nummatches > 0) {
2118 char *mbuf;
2119 int mlen = 0, maxmbuf = 2048;
2120 /* Start with a 2048 byte buffer */
2121 if (!(mbuf = ast_malloc(maxmbuf)))
2122 return (char *)(CC_ERROR);
2123 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2124 fdsend(ast_consock, buf);
2125 res = 0;
2126 mbuf[0] = '\0';
2127 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2128 if (mlen + 1024 > maxmbuf) {
2129 /* Every step increment buffer 1024 bytes */
2130 maxmbuf += 1024;
2131 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2132 return (char *)(CC_ERROR);
2134 /* Only read 1024 bytes at a time */
2135 res = read(ast_consock, mbuf + mlen, 1024);
2136 if (res > 0)
2137 mlen += res;
2139 mbuf[mlen] = '\0';
2141 matches = ast_el_strtoarr(mbuf);
2142 free(mbuf);
2143 } else
2144 matches = (char **) NULL;
2145 } else {
2146 char **p, *oldbuf=NULL;
2147 nummatches = 0;
2148 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2149 for (p = matches; p && *p; p++) {
2150 if (!oldbuf || strcmp(*p,oldbuf))
2151 nummatches++;
2152 oldbuf = *p;
2156 if (matches) {
2157 int i;
2158 int matches_num, maxlen, match_len;
2160 if (matches[0][0] != '\0') {
2161 el_deletestr(el, (int) len);
2162 el_insertstr(el, matches[0]);
2163 retval = CC_REFRESH;
2166 if (nummatches == 1) {
2167 /* Found an exact match */
2168 el_insertstr(el, " ");
2169 retval = CC_REFRESH;
2170 } else {
2171 /* Must be more than one match */
2172 for (i=1, maxlen=0; matches[i]; i++) {
2173 match_len = strlen(matches[i]);
2174 if (match_len > maxlen)
2175 maxlen = match_len;
2177 matches_num = i - 1;
2178 if (matches_num >1) {
2179 fprintf(stdout, "\n");
2180 ast_cli_display_match_list(matches, nummatches, maxlen);
2181 retval = CC_REDISPLAY;
2182 } else {
2183 el_insertstr(el," ");
2184 retval = CC_REFRESH;
2187 for (i = 0; matches[i]; i++)
2188 free(matches[i]);
2189 free(matches);
2192 return (char *)(long)retval;
2195 static int ast_el_initialize(void)
2197 HistEvent ev;
2198 char *editor = getenv("AST_EDITOR");
2200 if (el != NULL)
2201 el_end(el);
2202 if (el_hist != NULL)
2203 history_end(el_hist);
2205 el = el_init("asterisk", stdin, stdout, stderr);
2206 el_set(el, EL_PROMPT, cli_prompt);
2208 el_set(el, EL_EDITMODE, 1);
2209 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2210 el_hist = history_init();
2211 if (!el || !el_hist)
2212 return -1;
2214 /* setup history with 100 entries */
2215 history(el_hist, &ev, H_SETSIZE, 100);
2217 el_set(el, EL_HIST, history, el_hist);
2219 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2220 /* Bind <tab> to command completion */
2221 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2222 /* Bind ? to command completion */
2223 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2224 /* Bind ^D to redisplay */
2225 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2227 return 0;
2230 static int ast_el_add_history(char *buf)
2232 HistEvent ev;
2234 if (el_hist == NULL || el == NULL)
2235 ast_el_initialize();
2236 if (strlen(buf) > 256)
2237 return 0;
2238 return (history(el_hist, &ev, H_ENTER, buf));
2241 static int ast_el_write_history(char *filename)
2243 HistEvent ev;
2245 if (el_hist == NULL || el == NULL)
2246 ast_el_initialize();
2248 return (history(el_hist, &ev, H_SAVE, filename));
2251 static int ast_el_read_history(char *filename)
2253 char buf[256];
2254 FILE *f;
2255 int ret = -1;
2257 if (el_hist == NULL || el == NULL)
2258 ast_el_initialize();
2260 if ((f = fopen(filename, "r")) == NULL)
2261 return ret;
2263 while (!feof(f)) {
2264 fgets(buf, sizeof(buf), f);
2265 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2266 continue;
2267 if (ast_all_zeros(buf))
2268 continue;
2269 if ((ret = ast_el_add_history(buf)) == -1)
2270 break;
2272 fclose(f);
2274 return ret;
2277 static void ast_remotecontrol(char * data)
2279 char buf[80];
2280 int res;
2281 char filename[80] = "";
2282 char *hostname;
2283 char *cpid;
2284 char *version;
2285 int pid;
2286 char tmp[80];
2287 char *stringp = NULL;
2289 char *ebuf;
2290 int num = 0;
2292 read(ast_consock, buf, sizeof(buf));
2293 if (data)
2294 write(ast_consock, data, strlen(data) + 1);
2295 stringp = buf;
2296 hostname = strsep(&stringp, "/");
2297 cpid = strsep(&stringp, "/");
2298 version = strsep(&stringp, "\n");
2299 if (!version)
2300 version = "<Version Unknown>";
2301 stringp = hostname;
2302 strsep(&stringp, ".");
2303 if (cpid)
2304 pid = atoi(cpid);
2305 else
2306 pid = -1;
2307 if (!data) {
2308 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2309 fdsend(ast_consock, tmp);
2310 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2311 fdsend(ast_consock, tmp);
2312 if (!ast_opt_mute)
2313 fdsend(ast_consock, "logger mute silent");
2314 else
2315 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2317 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2318 remotehostname = hostname;
2319 if (getenv("HOME"))
2320 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2321 if (el_hist == NULL || el == NULL)
2322 ast_el_initialize();
2324 el_set(el, EL_GETCFN, ast_el_read_char);
2326 if (!ast_strlen_zero(filename))
2327 ast_el_read_history(filename);
2329 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2330 struct pollfd fds;
2331 fds.fd = ast_consock;
2332 fds.events = POLLIN;
2333 fds.revents = 0;
2334 while (poll(&fds, 1, 500) > 0) {
2335 char buf[512] = "", *curline = buf, *nextline;
2336 int not_written = 1;
2338 if (read(ast_consock, buf, sizeof(buf) - 1) <= 0) {
2339 break;
2342 do {
2343 if ((nextline = strchr(curline, '\n'))) {
2344 nextline++;
2345 } else {
2346 nextline = strchr(curline, '\0');
2349 /* Skip verbose lines */
2350 if (*curline != 127) {
2351 not_written = 0;
2352 write(STDOUT_FILENO, curline, nextline - curline);
2354 curline = nextline;
2355 } while (!ast_strlen_zero(curline));
2357 /* No non-verbose output in 500ms */
2358 if (not_written) {
2359 break;
2362 return;
2364 for (;;) {
2365 ebuf = (char *)el_gets(el, &num);
2367 if (!ebuf && write(1, "", 1) < 0)
2368 break;
2370 if (!ast_strlen_zero(ebuf)) {
2371 if (ebuf[strlen(ebuf)-1] == '\n')
2372 ebuf[strlen(ebuf)-1] = '\0';
2373 if (!remoteconsolehandler(ebuf)) {
2374 /* Strip preamble from output */
2375 char *tmp;
2376 for (tmp = ebuf; *tmp; tmp++) {
2377 if (*tmp == 127) {
2378 memmove(tmp, tmp + 1, strlen(tmp));
2379 tmp--;
2382 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2383 if (res < 1) {
2384 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2385 break;
2390 printf("\nDisconnected from Asterisk server\n");
2393 static int show_version(void)
2395 printf("Asterisk " ASTERISK_VERSION "\n");
2396 return 0;
2399 static int show_cli_help(void) {
2400 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008, Digium, Inc. and others.\n");
2401 printf("Usage: asterisk [OPTIONS]\n");
2402 printf("Valid Options:\n");
2403 printf(" -V Display version number and exit\n");
2404 printf(" -C <configfile> Use an alternate configuration file\n");
2405 printf(" -G <group> Run as a group other than the caller\n");
2406 printf(" -U <user> Run as a user other than the caller\n");
2407 printf(" -c Provide console CLI\n");
2408 printf(" -d Enable extra debugging\n");
2409 #if HAVE_WORKING_FORK
2410 printf(" -f Do not fork\n");
2411 printf(" -F Always fork\n");
2412 #endif
2413 printf(" -g Dump core in case of a crash\n");
2414 printf(" -h This help screen\n");
2415 printf(" -i Initialize crypto keys at startup\n");
2416 printf(" -I Enable internal timing if %s timer is available\n", dahdi_chan_name);
2417 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2418 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2419 printf(" -m Mute debugging and console output on the console\n");
2420 printf(" -n Disable console colorization\n");
2421 printf(" -p Run as pseudo-realtime thread\n");
2422 printf(" -q Quiet mode (suppress output)\n");
2423 printf(" -r Connect to Asterisk on this machine\n");
2424 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2425 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2426 printf(" belong after they are done\n");
2427 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2428 printf(" of output to the CLI\n");
2429 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2430 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2431 printf("\n");
2432 return 0;
2435 static void ast_readconfig(void)
2437 struct ast_config *cfg;
2438 struct ast_variable *v;
2439 char *config = AST_CONFIG_FILE;
2441 if (ast_opt_override_config) {
2442 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2443 if (!cfg)
2444 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2445 } else {
2446 cfg = ast_config_load(config);
2449 /* init with buildtime config */
2450 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2451 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2452 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2453 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2454 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2455 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2456 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2457 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2458 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2459 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2460 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2461 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2462 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2464 /* no asterisk.conf? no problem, use buildtime config! */
2465 if (!cfg) {
2466 return;
2469 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2470 if (!strcasecmp(v->name, "astctlpermissions")) {
2471 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2472 } else if (!strcasecmp(v->name, "astctlowner")) {
2473 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2474 } else if (!strcasecmp(v->name, "astctlgroup")) {
2475 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2476 } else if (!strcasecmp(v->name, "astctl")) {
2477 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2481 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2482 if (!strcasecmp(v->name, "astetcdir")) {
2483 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2484 } else if (!strcasecmp(v->name, "astspooldir")) {
2485 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2486 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2487 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2488 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2489 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2490 } else if (!strcasecmp(v->name, "astdatadir")) {
2491 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2492 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2493 } else if (!strcasecmp(v->name, "astlogdir")) {
2494 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2495 } else if (!strcasecmp(v->name, "astagidir")) {
2496 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2497 } else if (!strcasecmp(v->name, "astrundir")) {
2498 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2499 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2500 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2501 } else if (!strcasecmp(v->name, "astmoddir")) {
2502 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2506 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2507 /* verbose level (-v at startup) */
2508 if (!strcasecmp(v->name, "verbose")) {
2509 option_verbose = atoi(v->value);
2510 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2511 } else if (!strcasecmp(v->name, "timestamp")) {
2512 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2513 /* whether or not to support #exec in config files */
2514 } else if (!strcasecmp(v->name, "execincludes")) {
2515 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2516 /* debug level (-d at startup) */
2517 } else if (!strcasecmp(v->name, "debug")) {
2518 option_debug = 0;
2519 if (sscanf(v->value, "%d", &option_debug) != 1) {
2520 option_debug = ast_true(v->value);
2522 #if HAVE_WORKING_FORK
2523 /* Disable forking (-f at startup) */
2524 } else if (!strcasecmp(v->name, "nofork")) {
2525 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2526 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2527 } else if (!strcasecmp(v->name, "alwaysfork")) {
2528 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2529 #endif
2530 /* Run quietly (-q at startup ) */
2531 } else if (!strcasecmp(v->name, "quiet")) {
2532 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2533 /* Run as console (-c at startup, implies nofork) */
2534 } else if (!strcasecmp(v->name, "console")) {
2535 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2536 /* Run with high priority if the O/S permits (-p at startup) */
2537 } else if (!strcasecmp(v->name, "highpriority")) {
2538 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2539 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2540 } else if (!strcasecmp(v->name, "initcrypto")) {
2541 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2542 /* Disable ANSI colors for console (-c at startup) */
2543 } else if (!strcasecmp(v->name, "nocolor")) {
2544 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2545 /* Disable some usage warnings for picky people :p */
2546 } else if (!strcasecmp(v->name, "dontwarn")) {
2547 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2548 /* Dump core in case of crash (-g) */
2549 } else if (!strcasecmp(v->name, "dumpcore")) {
2550 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2551 /* Cache recorded sound files to another directory during recording */
2552 } else if (!strcasecmp(v->name, "cache_record_files")) {
2553 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2554 /* Specify cache directory */
2555 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2556 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2557 /* Build transcode paths via SLINEAR, instead of directly */
2558 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2559 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2560 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2561 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2562 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2563 /* Enable internal timing */
2564 } else if (!strcasecmp(v->name, "internal_timing")) {
2565 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2566 } else if (!strcasecmp(v->name, "maxcalls")) {
2567 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2568 option_maxcalls = 0;
2570 } else if (!strcasecmp(v->name, "maxload")) {
2571 double test[1];
2573 if (getloadavg(test, 1) == -1) {
2574 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2575 option_maxload = 0.0;
2576 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2577 option_maxload = 0.0;
2579 /* What user to run as */
2580 } else if (!strcasecmp(v->name, "runuser")) {
2581 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2582 /* What group to run as */
2583 } else if (!strcasecmp(v->name, "rungroup")) {
2584 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2585 } else if (!strcasecmp(v->name, "systemname")) {
2586 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2587 } else if (!strcasecmp(v->name, "languageprefix")) {
2588 ast_language_is_prefix = ast_true(v->value);
2589 } else if (!strcasecmp(v->name, "dahdichanname")) {
2590 #ifdef HAVE_ZAPTEL
2591 if (ast_true(v->value)) {
2592 strcpy(_dahdi_chan_name, "DAHDI");
2593 _dahdi_chan_name_len = 5;
2594 _dahdi_chan_mode = CHAN_DAHDI_PLUS_ZAP_MODE;
2596 #else
2597 if (ast_false(v->value)) {
2598 strcpy(_dahdi_chan_name, "Zap");
2599 _dahdi_chan_name_len = 3;
2600 _dahdi_chan_mode = CHAN_ZAP_MODE;
2602 #endif
2605 ast_config_destroy(cfg);
2608 static void *monitor_sig_flags(void *unused)
2610 for (;;) {
2611 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2612 int a;
2613 poll(&p, 1, -1);
2614 if (sig_flags.need_reload) {
2615 sig_flags.need_reload = 0;
2616 ast_module_reload(NULL);
2618 if (sig_flags.need_quit) {
2619 sig_flags.need_quit = 0;
2620 quit_handler(0, 0, 1, 0);
2622 read(sig_alert_pipe[0], &a, sizeof(a));
2625 return NULL;
2628 int main(int argc, char *argv[])
2630 int c;
2631 char filename[80] = "";
2632 char hostname[MAXHOSTNAMELEN] = "";
2633 char tmp[80];
2634 char * xarg = NULL;
2635 int x;
2636 FILE *f;
2637 sigset_t sigs;
2638 int num;
2639 int isroot = 1;
2640 char *buf;
2641 char *runuser = NULL, *rungroup = NULL;
2643 /* Remember original args for restart */
2644 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2645 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2646 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2648 for (x=0; x<argc; x++)
2649 _argv[x] = argv[x];
2650 _argv[x] = NULL;
2652 if (geteuid() != 0)
2653 isroot = 0;
2655 /* if the progname is rasterisk consider it a remote console */
2656 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2657 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2659 if (gethostname(hostname, sizeof(hostname)-1))
2660 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2661 ast_mainpid = getpid();
2662 ast_ulaw_init();
2663 ast_alaw_init();
2664 callerid_init();
2665 ast_builtins_init();
2666 ast_utils_init();
2667 tdd_init();
2669 if (getenv("HOME"))
2670 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2671 /* Check for options */
2672 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2673 switch (c) {
2674 #if HAVE_WORKING_FORK
2675 case 'F':
2676 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2677 break;
2678 case 'f':
2679 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2680 break;
2681 #endif
2682 case 'd':
2683 option_debug++;
2684 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2685 break;
2686 case 'c':
2687 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2688 break;
2689 case 'n':
2690 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2691 break;
2692 case 'r':
2693 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2694 break;
2695 case 'R':
2696 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2697 break;
2698 case 'p':
2699 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2700 break;
2701 case 'v':
2702 option_verbose++;
2703 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2704 break;
2705 case 'm':
2706 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2707 break;
2708 case 'M':
2709 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2710 option_maxcalls = 0;
2711 break;
2712 case 'L':
2713 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2714 option_maxload = 0.0;
2715 break;
2716 case 'q':
2717 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2718 break;
2719 case 't':
2720 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2721 break;
2722 case 'T':
2723 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2724 break;
2725 case 'x':
2726 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2727 xarg = ast_strdupa(optarg);
2728 break;
2729 case 'C':
2730 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2731 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2732 break;
2733 case 'I':
2734 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2735 break;
2736 case 'i':
2737 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2738 break;
2739 case 'g':
2740 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2741 break;
2742 case 'h':
2743 show_cli_help();
2744 exit(0);
2745 case 'V':
2746 show_version();
2747 exit(0);
2748 case 'U':
2749 runuser = ast_strdupa(optarg);
2750 break;
2751 case 'G':
2752 rungroup = ast_strdupa(optarg);
2753 break;
2754 case '?':
2755 exit(1);
2759 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2760 ast_register_verbose(console_verboser);
2761 WELCOME_MESSAGE;
2764 if (ast_opt_console && !option_verbose)
2765 ast_verbose("[ Booting...\n");
2767 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2768 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2769 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2772 /* For remote connections, change the name of the remote connection.
2773 * We do this for the benefit of init scripts (which need to know if/when
2774 * the main asterisk process has died yet). */
2775 if (ast_opt_remote) {
2776 strcpy(argv[0], "rasterisk");
2777 for (x = 1; x < argc; x++) {
2778 argv[x] = argv[0] + 10;
2782 if (ast_opt_console && !option_verbose)
2783 ast_verbose("[ Reading Master Configuration ]\n");
2784 ast_readconfig();
2786 if (ast_opt_dump_core) {
2787 struct rlimit l;
2788 memset(&l, 0, sizeof(l));
2789 l.rlim_cur = RLIM_INFINITY;
2790 l.rlim_max = RLIM_INFINITY;
2791 if (setrlimit(RLIMIT_CORE, &l)) {
2792 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2796 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2797 rungroup = ast_config_AST_RUN_GROUP;
2798 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2799 runuser = ast_config_AST_RUN_USER;
2801 #ifndef __CYGWIN__
2803 if (isroot)
2804 ast_set_priority(ast_opt_high_priority);
2806 if (isroot && rungroup) {
2807 struct group *gr;
2808 gr = getgrnam(rungroup);
2809 if (!gr) {
2810 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2811 exit(1);
2813 if (setgid(gr->gr_gid)) {
2814 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2815 exit(1);
2817 if (setgroups(0, NULL)) {
2818 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2819 exit(1);
2821 if (option_verbose)
2822 ast_verbose("Running as group '%s'\n", rungroup);
2825 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
2826 #ifdef HAVE_CAP
2827 int has_cap = 1;
2828 #endif /* HAVE_CAP */
2829 struct passwd *pw;
2830 pw = getpwnam(runuser);
2831 if (!pw) {
2832 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2833 exit(1);
2835 #ifdef HAVE_CAP
2836 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
2837 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
2838 has_cap = 0;
2840 #endif /* HAVE_CAP */
2841 if (!isroot && pw->pw_uid != geteuid()) {
2842 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
2843 exit(1);
2845 if (!rungroup) {
2846 if (setgid(pw->pw_gid)) {
2847 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2848 exit(1);
2850 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
2851 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2852 exit(1);
2855 if (setuid(pw->pw_uid)) {
2856 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2857 exit(1);
2859 if (option_verbose)
2860 ast_verbose("Running as user '%s'\n", runuser);
2861 #ifdef HAVE_CAP
2862 if (has_cap) {
2863 cap_t cap;
2865 cap = cap_from_text("cap_net_admin=ep");
2867 if (cap_set_proc(cap))
2868 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
2870 if (cap_free(cap))
2871 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
2873 #endif /* HAVE_CAP */
2876 #endif /* __CYGWIN__ */
2878 #ifdef linux
2879 if (geteuid() && ast_opt_dump_core) {
2880 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2881 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2884 #endif
2886 ast_term_init();
2887 printf(term_end());
2888 fflush(stdout);
2890 if (ast_opt_console && !option_verbose)
2891 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2892 /* custom config setup */
2893 register_config_cli();
2894 read_config_maps();
2896 if (ast_opt_console) {
2897 if (el_hist == NULL || el == NULL)
2898 ast_el_initialize();
2900 if (!ast_strlen_zero(filename))
2901 ast_el_read_history(filename);
2904 if (ast_tryconnect()) {
2905 /* One is already running */
2906 if (ast_opt_remote) {
2907 if (ast_opt_exec) {
2908 ast_remotecontrol(xarg);
2909 quit_handler(0, 0, 0, 0);
2910 exit(0);
2912 printf(term_quit());
2913 ast_remotecontrol(NULL);
2914 quit_handler(0, 0, 0, 0);
2915 exit(0);
2916 } else {
2917 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2918 printf(term_quit());
2919 exit(1);
2921 } else if (ast_opt_remote || ast_opt_exec) {
2922 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2923 printf(term_quit());
2924 exit(1);
2926 /* Blindly write pid file since we couldn't connect */
2927 unlink(ast_config_AST_PID);
2928 f = fopen(ast_config_AST_PID, "w");
2929 if (f) {
2930 fprintf(f, "%ld\n", (long)getpid());
2931 fclose(f);
2932 } else
2933 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2935 #if HAVE_WORKING_FORK
2936 if (ast_opt_always_fork || !ast_opt_no_fork) {
2937 #ifndef HAVE_SBIN_LAUNCHD
2938 daemon(1, 0);
2939 ast_mainpid = getpid();
2940 /* Blindly re-write pid file since we are forking */
2941 unlink(ast_config_AST_PID);
2942 f = fopen(ast_config_AST_PID, "w");
2943 if (f) {
2944 fprintf(f, "%ld\n", (long)ast_mainpid);
2945 fclose(f);
2946 } else
2947 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2948 #else
2949 ast_log(LOG_WARNING, "Mac OS X detected. Use '/sbin/launchd -d' to launch with the nofork option.\n");
2950 #endif
2952 #endif
2954 /* Test recursive mutex locking. */
2955 if (test_for_thread_safety())
2956 ast_verbose("Warning! Asterisk is not thread safe.\n");
2958 ast_makesocket();
2959 sigemptyset(&sigs);
2960 sigaddset(&sigs, SIGHUP);
2961 sigaddset(&sigs, SIGTERM);
2962 sigaddset(&sigs, SIGINT);
2963 sigaddset(&sigs, SIGPIPE);
2964 sigaddset(&sigs, SIGWINCH);
2965 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2966 signal(SIGURG, urg_handler);
2967 signal(SIGINT, __quit_handler);
2968 signal(SIGTERM, __quit_handler);
2969 signal(SIGHUP, hup_handler);
2970 signal(SIGCHLD, child_handler);
2971 signal(SIGPIPE, SIG_IGN);
2973 /* ensure that the random number generators are seeded with a different value every time
2974 Asterisk is started
2976 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2977 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2979 if (init_logger()) {
2980 printf(term_quit());
2981 exit(1);
2984 dahdi_chan_name = _dahdi_chan_name;
2985 dahdi_chan_name_len = &_dahdi_chan_name_len;
2986 dahdi_chan_mode = &_dahdi_chan_mode;
2988 #ifdef HAVE_ZAPTEL
2990 int fd;
2991 int x = 160;
2992 fd = open("/dev/zap/timer", O_RDWR);
2993 if (fd >= 0) {
2994 if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
2995 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);
2996 exit(1);
2998 if ((x = ast_wait_for_input(fd, 300)) < 0) {
2999 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");
3000 exit(1);
3002 if (!x) {
3003 const char zaptel_timer_error[] = {
3004 "Asterisk has detected a problem with your Zaptel configuration and will shutdown for your protection. You have options:"
3005 "\n\t1. You only have to compile Zaptel support into Asterisk if you need it. One option is to recompile without Zaptel support."
3006 "\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."
3007 "\n\t3. If you need Zaptel services, you must correctly configure Zaptel."
3009 ast_log(LOG_ERROR, "%s\n", zaptel_timer_error);
3010 exit(1);
3012 close(fd);
3015 #elif defined(HAVE_DAHDI)
3017 int fd;
3018 int x = 160;
3019 fd = open("/dev/dahdi/timer", O_RDWR);
3020 if (fd >= 0) {
3021 if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
3022 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);
3023 exit(1);
3025 if ((x = ast_wait_for_input(fd, 300)) < 0) {
3026 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");
3027 exit(1);
3029 if (!x) {
3030 const char dahdi_timer_error[] = {
3031 "Asterisk has detected a problem with your DAHDI configuration and will shutdown for your protection. You have options:"
3032 "\n\t1. You only have to compile DAHDI support into Asterisk if you need it. One option is to recompile without DAHDI support."
3033 "\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."
3034 "\n\t3. If you need DAHDI services, you must correctly configure DAHDI."
3036 ast_log(LOG_ERROR, "%s\n", dahdi_timer_error);
3037 exit(1);
3039 close(fd);
3043 #endif
3044 threadstorage_init();
3046 astobj2_init();
3048 ast_autoservice_init();
3050 if (load_modules(1)) {
3051 printf(term_quit());
3052 exit(1);
3055 if (dnsmgr_init()) {
3056 printf(term_quit());
3057 exit(1);
3060 ast_http_init();
3062 ast_channels_init();
3064 if (init_manager()) {
3065 printf(term_quit());
3066 exit(1);
3069 if (ast_cdr_engine_init()) {
3070 printf(term_quit());
3071 exit(1);
3074 if (ast_device_state_engine_init()) {
3075 printf(term_quit());
3076 exit(1);
3079 ast_rtp_init();
3081 ast_udptl_init();
3083 if (ast_image_init()) {
3084 printf(term_quit());
3085 exit(1);
3088 if (ast_file_init()) {
3089 printf(term_quit());
3090 exit(1);
3093 if (load_pbx()) {
3094 printf(term_quit());
3095 exit(1);
3098 if (init_framer()) {
3099 printf(term_quit());
3100 exit(1);
3103 if (astdb_init()) {
3104 printf(term_quit());
3105 exit(1);
3108 if (ast_enum_init()) {
3109 printf(term_quit());
3110 exit(1);
3113 if (load_modules(0)) {
3114 printf(term_quit());
3115 exit(1);
3118 dnsmgr_start_refresh();
3120 /* We might have the option of showing a console, but for now just
3121 do nothing... */
3122 if (ast_opt_console && !option_verbose)
3123 ast_verbose(" ]\n");
3124 if (option_verbose || ast_opt_console)
3125 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
3126 if (ast_opt_no_fork)
3127 consolethread = pthread_self();
3129 if (pipe(sig_alert_pipe))
3130 sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
3132 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
3133 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
3135 #ifdef __AST_DEBUG_MALLOC
3136 __ast_mm_init();
3137 #endif
3139 time(&ast_startuptime);
3140 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
3142 if (ast_opt_console) {
3143 /* Console stuff now... */
3144 /* Register our quit function */
3145 char title[256];
3146 pthread_attr_t attr;
3147 pthread_t dont_care;
3149 pthread_attr_init(&attr);
3150 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3151 ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);
3152 pthread_attr_destroy(&attr);
3154 set_icon("Asterisk");
3155 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
3156 set_title(title);
3158 for (;;) {
3159 buf = (char *)el_gets(el, &num);
3161 if (!buf && write(1, "", 1) < 0)
3162 goto lostterm;
3164 if (buf) {
3165 if (buf[strlen(buf)-1] == '\n')
3166 buf[strlen(buf)-1] = '\0';
3168 consolehandler((char *)buf);
3169 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
3170 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
3171 /* Whoa, stdout disappeared from under us... Make /dev/null's */
3172 int fd;
3173 fd = open("/dev/null", O_RDWR);
3174 if (fd > -1) {
3175 dup2(fd, STDOUT_FILENO);
3176 dup2(fd, STDIN_FILENO);
3177 } else
3178 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
3179 break;
3184 monitor_sig_flags(NULL);
3186 lostterm:
3187 return 0;