remove the dlfcn compatibility stuff, because no platforms that Asterisk currently...
[asterisk-bristuff.git] / main / asterisk.c
blob36a65c91a8dcac15237143fb0eb2843c3e293126
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2008, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
21 /*!
22 * \mainpage Asterisk -- An Open Source Telephony Toolkit
24 * \par Developer Documentation for Asterisk
25 * This is the main developer documentation for Asterisk. It is
26 * generated by running "make progdocs".
27 * \par Additional documentation
28 * \arg \ref DevDoc
29 * \arg \ref ConfigFiles
31 * \section copyright Copyright and author
33 * Copyright (C) 1999 - 2008, Digium, Inc.
34 * Asterisk is a trademark registered by Digium, Inc.
36 * \author Mark Spencer <markster@digium.com>
37 * Also see \ref AstCREDITS
39 * \section license License
40 * See http://www.asterisk.org for more information about
41 * the Asterisk project. Please do not directly contact
42 * any of the maintainers of this project for assistance;
43 * the project provides a web site, mailing lists and IRC
44 * channels for your use.
46 * This program is free software, distributed under the terms of
47 * the GNU General Public License Version 2. See the LICENSE file
48 * at the top of the source tree.
50 * \verbinclude LICENSE
54 /*! \file
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
60 #include "asterisk.h"
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
64 #undef sched_setscheduler
65 #undef setpriority
66 #include <unistd.h>
67 #include <stdlib.h>
68 #include <sys/time.h>
69 #include <fcntl.h>
70 #include <stdio.h>
71 #include <signal.h>
72 #include <sched.h>
73 #include <sys/socket.h>
74 #include <sys/un.h>
75 #include <sys/wait.h>
76 #include <string.h>
77 #include <errno.h>
78 #include <ctype.h>
79 #include <sys/resource.h>
80 #include <grp.h>
81 #include <pwd.h>
82 #include <sys/stat.h>
84 #if defined(HAVE_ZAPTEL) || defined (HAVE_DAHDI)
85 #include <sys/ioctl.h>
86 #include "asterisk/dahdi_compat.h"
87 #endif
89 #ifdef linux
90 #include <sys/prctl.h>
91 #ifdef HAVE_CAP
92 #include <sys/capability.h>
93 #endif /* HAVE_CAP */
94 #endif /* linux */
95 #include <regex.h>
97 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
98 #include <netdb.h>
99 #if defined(SOLARIS)
100 int daemon(int, int); /* defined in libresolv of all places */
101 #endif
102 #endif
104 #include "asterisk/logger.h"
105 #include "asterisk/options.h"
106 #include "asterisk/cli.h"
107 #include "asterisk/channel.h"
108 #include "asterisk/ulaw.h"
109 #include "asterisk/alaw.h"
110 #include "asterisk/callerid.h"
111 #include "asterisk/image.h"
112 #include "asterisk/tdd.h"
113 #include "asterisk/term.h"
114 #include "asterisk/manager.h"
115 #include "asterisk/cdr.h"
116 #include "asterisk/pbx.h"
117 #include "asterisk/enum.h"
118 #include "asterisk/rtp.h"
119 #include "asterisk/http.h"
120 #include "asterisk/udptl.h"
121 #include "asterisk/app.h"
122 #include "asterisk/lock.h"
123 #include "asterisk/utils.h"
124 #include "asterisk/file.h"
125 #include "asterisk/io.h"
126 #include "asterisk/lock.h"
127 #include "editline/histedit.h"
128 #include "asterisk/config.h"
129 #include "asterisk/version.h"
130 #include "asterisk/linkedlists.h"
131 #include "asterisk/devicestate.h"
132 #include "asterisk/module.h"
134 #include "asterisk/doxyref.h" /* Doxygen documentation */
136 #include "../defaults.h"
138 #ifndef AF_LOCAL
139 #define AF_LOCAL AF_UNIX
140 #define PF_LOCAL PF_UNIX
141 #endif
143 #define AST_MAX_CONNECTS 128
144 #define NUM_MSGS 64
146 /*! \brief Welcome message when starting a CLI interface */
147 #define WELCOME_MESSAGE \
148 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008 Digium, Inc. and others.\n"); \
149 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
150 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
151 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
152 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
153 ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
154 ast_verbose("=========================================================================\n")
156 /*! \defgroup main_options Main Configuration Options
157 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
158 the operating system command line when starting Asterisk
159 Some of them can be changed in the CLI
161 /*! @{ */
163 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
165 int option_verbose; /*!< Verbosity level */
166 int option_debug; /*!< Debug level */
168 double option_maxload; /*!< Max load avg on system */
169 int option_maxcalls; /*!< Max number of active calls */
171 /*! @} */
173 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
174 char debug_filename[AST_FILENAME_MAX] = "";
175 #ifdef HAVE_ZAPTEL
176 char _dahdi_chan_name[AST_CHANNEL_NAME] = "Zap";
177 enum dahdi_chan_modes dahdi_chan_mode = ZAP_ONLY_MODE;
178 #else
179 char _dahdi_chan_name[AST_CHANNEL_NAME] = "DAHDI";
180 enum dahdi_chan_modes dahdi_chan_mode = DAHDI_PLUS_ZAP;
181 #endif
182 const char *dahdi_chan_name;
184 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
185 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
186 pid_t ast_mainpid;
187 struct console {
188 int fd; /*!< File descriptor */
189 int p[2]; /*!< Pipe */
190 pthread_t t; /*!< Thread of handler */
191 int mute; /*!< Is the console muted for logs */
194 struct ast_atexit {
195 void (*func)(void);
196 AST_LIST_ENTRY(ast_atexit) list;
199 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
201 time_t ast_startuptime;
202 time_t ast_lastreloadtime;
204 static History *el_hist;
205 static EditLine *el;
206 static char *remotehostname;
208 struct console consoles[AST_MAX_CONNECTS];
210 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
212 static int ast_el_add_history(char *);
213 static int ast_el_read_history(char *);
214 static int ast_el_write_history(char *);
216 char ast_config_AST_CONFIG_DIR[PATH_MAX];
217 char ast_config_AST_CONFIG_FILE[PATH_MAX];
218 char ast_config_AST_MODULE_DIR[PATH_MAX];
219 char ast_config_AST_SPOOL_DIR[PATH_MAX];
220 char ast_config_AST_MONITOR_DIR[PATH_MAX];
221 char ast_config_AST_VAR_DIR[PATH_MAX];
222 char ast_config_AST_DATA_DIR[PATH_MAX];
223 char ast_config_AST_LOG_DIR[PATH_MAX];
224 char ast_config_AST_AGI_DIR[PATH_MAX];
225 char ast_config_AST_DB[PATH_MAX];
226 char ast_config_AST_KEY_DIR[PATH_MAX];
227 char ast_config_AST_PID[PATH_MAX];
228 char ast_config_AST_SOCKET[PATH_MAX];
229 char ast_config_AST_RUN_DIR[PATH_MAX];
230 char ast_config_AST_RUN_USER[PATH_MAX];
231 char ast_config_AST_RUN_GROUP[PATH_MAX];
232 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
233 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
234 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
235 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
236 char ast_config_AST_SYSTEM_NAME[20] = "";
238 extern const char *ast_build_hostname;
239 extern const char *ast_build_kernel;
240 extern const char *ast_build_machine;
241 extern const char *ast_build_os;
242 extern const char *ast_build_date;
243 extern const char *ast_build_user;
245 static char *_argv[256];
246 static int shuttingdown;
247 static int restartnow;
248 static pthread_t consolethread = AST_PTHREADT_NULL;
250 static char randompool[256];
252 static int sig_alert_pipe[2] = { -1, -1 };
253 static struct {
254 unsigned int need_reload:1;
255 unsigned int need_quit:1;
256 } sig_flags;
258 #if !defined(LOW_MEMORY)
259 struct file_version {
260 AST_LIST_ENTRY(file_version) list;
261 const char *file;
262 char *version;
265 static AST_LIST_HEAD_STATIC(file_versions, file_version);
267 void ast_register_file_version(const char *file, const char *version)
269 struct file_version *new;
270 char *work;
271 size_t version_length;
273 work = ast_strdupa(version);
274 work = ast_strip(ast_strip_quoted(work, "$", "$"));
275 version_length = strlen(work) + 1;
277 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
278 return;
280 new->file = file;
281 new->version = (char *) new + sizeof(*new);
282 memcpy(new->version, work, version_length);
283 AST_LIST_LOCK(&file_versions);
284 AST_LIST_INSERT_HEAD(&file_versions, new, list);
285 AST_LIST_UNLOCK(&file_versions);
288 void ast_unregister_file_version(const char *file)
290 struct file_version *find;
292 AST_LIST_LOCK(&file_versions);
293 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
294 if (!strcasecmp(find->file, file)) {
295 AST_LIST_REMOVE_CURRENT(&file_versions, list);
296 break;
299 AST_LIST_TRAVERSE_SAFE_END;
300 AST_LIST_UNLOCK(&file_versions);
301 if (find)
302 free(find);
305 struct thread_list_t {
306 AST_LIST_ENTRY(thread_list_t) list;
307 char *name;
308 pthread_t id;
311 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
313 static char show_threads_help[] =
314 "Usage: core show threads\n"
315 " List threads currently active in the system.\n";
317 void ast_register_thread(char *name)
319 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
321 if (!new)
322 return;
323 new->id = pthread_self();
324 new->name = name; /* steal the allocated memory for the thread name */
325 AST_LIST_LOCK(&thread_list);
326 AST_LIST_INSERT_HEAD(&thread_list, new, list);
327 AST_LIST_UNLOCK(&thread_list);
330 void ast_unregister_thread(void *id)
332 struct thread_list_t *x;
334 AST_LIST_LOCK(&thread_list);
335 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
336 if ((void *) x->id == id) {
337 AST_LIST_REMOVE_CURRENT(&thread_list, list);
338 break;
341 AST_LIST_TRAVERSE_SAFE_END;
342 AST_LIST_UNLOCK(&thread_list);
343 if (x) {
344 free(x->name);
345 free(x);
349 static int handle_show_threads(int fd, int argc, char *argv[])
351 int count = 0;
352 struct thread_list_t *cur;
354 AST_LIST_LOCK(&thread_list);
355 AST_LIST_TRAVERSE(&thread_list, cur, list) {
356 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
357 count++;
359 AST_LIST_UNLOCK(&thread_list);
360 ast_cli(fd, "%d threads listed.\n", count);
361 return 0;
364 struct profile_entry {
365 const char *name;
366 uint64_t scale; /* if non-zero, values are scaled by this */
367 int64_t mark;
368 int64_t value;
369 int64_t events;
372 struct profile_data {
373 int entries;
374 int max_size;
375 struct profile_entry e[0];
378 static struct profile_data *prof_data;
380 /*! \brief allocates a counter with a given name and scale.
381 * \return Returns the identifier of the counter.
383 int ast_add_profile(const char *name, uint64_t scale)
385 int l = sizeof(struct profile_data);
386 int n = 10; /* default entries */
388 if (prof_data == NULL) {
389 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
390 if (prof_data == NULL)
391 return -1;
392 prof_data->entries = 0;
393 prof_data->max_size = n;
395 if (prof_data->entries >= prof_data->max_size) {
396 void *p;
397 n = prof_data->max_size + 20;
398 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
399 if (p == NULL)
400 return -1;
401 prof_data = p;
402 prof_data->max_size = n;
404 n = prof_data->entries++;
405 prof_data->e[n].name = ast_strdup(name);
406 prof_data->e[n].value = 0;
407 prof_data->e[n].events = 0;
408 prof_data->e[n].mark = 0;
409 prof_data->e[n].scale = scale;
410 return n;
413 int64_t ast_profile(int i, int64_t delta)
415 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
416 return 0;
417 if (prof_data->e[i].scale > 1)
418 delta /= prof_data->e[i].scale;
419 prof_data->e[i].value += delta;
420 prof_data->e[i].events++;
421 return prof_data->e[i].value;
424 /* The RDTSC instruction was introduced on the Pentium processor and is not
425 * implemented on certain clones, like the Cyrix 586. Hence, the previous
426 * expectation of __i386__ was in error. */
427 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
428 #if defined(__FreeBSD__)
429 #include <machine/cpufunc.h>
430 #elif defined(linux)
431 static __inline uint64_t
432 rdtsc(void)
434 uint64_t rv;
436 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
437 return (rv);
439 #endif
440 #else /* supply a dummy function on other platforms */
441 static __inline uint64_t
442 rdtsc(void)
444 return 0;
446 #endif
448 int64_t ast_mark(int i, int startstop)
450 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
451 return 0;
452 if (startstop == 1)
453 prof_data->e[i].mark = rdtsc();
454 else {
455 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
456 if (prof_data->e[i].scale > 1)
457 prof_data->e[i].mark /= prof_data->e[i].scale;
458 prof_data->e[i].value += prof_data->e[i].mark;
459 prof_data->e[i].events++;
461 return prof_data->e[i].mark;
464 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
466 int i, min, max;
467 char *search = NULL;
469 if (prof_data == NULL)
470 return 0;
472 min = 0;
473 max = prof_data->entries;
474 if (argc >= 3) { /* specific entries */
475 if (isdigit(argv[2][0])) {
476 min = atoi(argv[2]);
477 if (argc == 4 && strcmp(argv[3], "-"))
478 max = atoi(argv[3]);
479 } else
480 search = argv[2];
482 if (max > prof_data->entries)
483 max = prof_data->entries;
484 if (!strcmp(argv[0], "clear")) {
485 for (i= min; i < max; i++) {
486 if (!search || strstr(prof_data->e[i].name, search)) {
487 prof_data->e[i].value = 0;
488 prof_data->e[i].events = 0;
491 return 0;
493 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
494 prof_data->entries, prof_data->max_size);
495 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
496 "Value", "Average", "Name");
497 for (i = min; i < max; i++) {
498 struct profile_entry *e = &prof_data->e[i];
499 if (!search || strstr(prof_data->e[i].name, search))
500 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
502 (long)e->scale,
503 (long)e->events, (long long)e->value,
504 (long long)(e->events ? e->value / e->events : e->value),
505 e->name);
507 return 0;
510 static int handle_show_profile(int fd, int argc, char *argv[])
512 int i, min, max;
513 char *search = NULL;
515 if (prof_data == NULL)
516 return 0;
518 min = 0;
519 max = prof_data->entries;
520 if (argc > 3) { /* specific entries */
521 if (isdigit(argv[3][0])) {
522 min = atoi(argv[3]);
523 if (argc == 5 && strcmp(argv[4], "-"))
524 max = atoi(argv[4]);
525 } else
526 search = argv[3];
528 if (max > prof_data->entries)
529 max = prof_data->entries;
530 if (!strcmp(argv[1], "clear")) {
531 for (i= min; i < max; i++) {
532 if (!search || strstr(prof_data->e[i].name, search)) {
533 prof_data->e[i].value = 0;
534 prof_data->e[i].events = 0;
537 return 0;
539 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
540 prof_data->entries, prof_data->max_size);
541 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
542 "Value", "Average", "Name");
543 for (i = min; i < max; i++) {
544 struct profile_entry *e = &prof_data->e[i];
545 if (!search || strstr(prof_data->e[i].name, search))
546 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
548 (long)e->scale,
549 (long)e->events, (long long)e->value,
550 (long long)(e->events ? e->value / e->events : e->value),
551 e->name);
553 return 0;
556 static char show_version_files_help[] =
557 "Usage: core show file version [like <pattern>]\n"
558 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
559 " Optional regular expression pattern is used to filter the file list.\n";
561 /*! \brief CLI command to list module versions */
562 static int handle_show_version_files_deprecated(int fd, int argc, char *argv[])
564 #define FORMAT "%-25.25s %-40.40s\n"
565 struct file_version *iterator;
566 regex_t regexbuf;
567 int havepattern = 0;
568 int havename = 0;
569 int count_files = 0;
571 switch (argc) {
572 case 5:
573 if (!strcasecmp(argv[3], "like")) {
574 if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
575 return RESULT_SHOWUSAGE;
576 havepattern = 1;
577 } else
578 return RESULT_SHOWUSAGE;
579 break;
580 case 4:
581 havename = 1;
582 break;
583 case 3:
584 break;
585 default:
586 return RESULT_SHOWUSAGE;
589 ast_cli(fd, FORMAT, "File", "Revision");
590 ast_cli(fd, FORMAT, "----", "--------");
591 AST_LIST_LOCK(&file_versions);
592 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
593 if (havename && strcasecmp(iterator->file, argv[3]))
594 continue;
596 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
597 continue;
599 ast_cli(fd, FORMAT, iterator->file, iterator->version);
600 count_files++;
601 if (havename)
602 break;
604 AST_LIST_UNLOCK(&file_versions);
605 if (!havename) {
606 ast_cli(fd, "%d files listed.\n", count_files);
609 if (havepattern)
610 regfree(&regexbuf);
612 return RESULT_SUCCESS;
613 #undef FORMAT
616 static int handle_show_version_files(int fd, int argc, char *argv[])
618 #define FORMAT "%-25.25s %-40.40s\n"
619 struct file_version *iterator;
620 regex_t regexbuf;
621 int havepattern = 0;
622 int havename = 0;
623 int count_files = 0;
625 switch (argc) {
626 case 6:
627 if (!strcasecmp(argv[4], "like")) {
628 if (regcomp(&regexbuf, argv[5], REG_EXTENDED | REG_NOSUB))
629 return RESULT_SHOWUSAGE;
630 havepattern = 1;
631 } else
632 return RESULT_SHOWUSAGE;
633 break;
634 case 5:
635 havename = 1;
636 break;
637 case 4:
638 break;
639 default:
640 return RESULT_SHOWUSAGE;
643 ast_cli(fd, FORMAT, "File", "Revision");
644 ast_cli(fd, FORMAT, "----", "--------");
645 AST_LIST_LOCK(&file_versions);
646 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
647 if (havename && strcasecmp(iterator->file, argv[4]))
648 continue;
650 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
651 continue;
653 ast_cli(fd, FORMAT, iterator->file, iterator->version);
654 count_files++;
655 if (havename)
656 break;
658 AST_LIST_UNLOCK(&file_versions);
659 if (!havename) {
660 ast_cli(fd, "%d files listed.\n", count_files);
663 if (havepattern)
664 regfree(&regexbuf);
666 return RESULT_SUCCESS;
667 #undef FORMAT
670 static char *complete_show_version_files_deprecated(const char *line, const char *word, int pos, int state)
672 struct file_version *find;
673 int which = 0;
674 char *ret = NULL;
675 int matchlen = strlen(word);
677 if (pos != 3)
678 return NULL;
680 AST_LIST_LOCK(&file_versions);
681 AST_LIST_TRAVERSE(&file_versions, find, list) {
682 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
683 ret = ast_strdup(find->file);
684 break;
687 AST_LIST_UNLOCK(&file_versions);
689 return ret;
692 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
694 struct file_version *find;
695 int which = 0;
696 char *ret = NULL;
697 int matchlen = strlen(word);
699 if (pos != 4)
700 return NULL;
702 AST_LIST_LOCK(&file_versions);
703 AST_LIST_TRAVERSE(&file_versions, find, list) {
704 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
705 ret = ast_strdup(find->file);
706 break;
709 AST_LIST_UNLOCK(&file_versions);
711 return ret;
714 #endif /* ! LOW_MEMORY */
716 int ast_register_atexit(void (*func)(void))
718 struct ast_atexit *ae;
720 if (!(ae = ast_calloc(1, sizeof(*ae))))
721 return -1;
723 ae->func = func;
725 ast_unregister_atexit(func);
727 AST_LIST_LOCK(&atexits);
728 AST_LIST_INSERT_HEAD(&atexits, ae, list);
729 AST_LIST_UNLOCK(&atexits);
731 return 0;
734 void ast_unregister_atexit(void (*func)(void))
736 struct ast_atexit *ae = NULL;
738 AST_LIST_LOCK(&atexits);
739 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
740 if (ae->func == func) {
741 AST_LIST_REMOVE_CURRENT(&atexits, list);
742 break;
745 AST_LIST_TRAVERSE_SAFE_END
746 AST_LIST_UNLOCK(&atexits);
748 if (ae)
749 free(ae);
752 /* Sending commands from consoles back to the daemon requires a terminating NULL */
753 static int fdsend(int fd, const char *s)
755 return write(fd, s, strlen(s) + 1);
758 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
759 static int fdprint(int fd, const char *s)
761 return write(fd, s, strlen(s));
764 /*! \brief NULL handler so we can collect the child exit status */
765 static void null_sig_handler(int signal)
770 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
771 /*! \brief Keep track of how many threads are currently trying to wait*() on
772 * a child process */
773 static unsigned int safe_system_level = 0;
774 static void *safe_system_prev_handler;
776 void ast_replace_sigchld(void)
778 unsigned int level;
780 ast_mutex_lock(&safe_system_lock);
781 level = safe_system_level++;
783 /* only replace the handler if it has not already been done */
784 if (level == 0)
785 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
787 ast_mutex_unlock(&safe_system_lock);
790 void ast_unreplace_sigchld(void)
792 unsigned int level;
794 ast_mutex_lock(&safe_system_lock);
795 level = --safe_system_level;
797 /* only restore the handler if we are the last one */
798 if (level == 0)
799 signal(SIGCHLD, safe_system_prev_handler);
801 ast_mutex_unlock(&safe_system_lock);
804 int ast_safe_system(const char *s)
806 pid_t pid;
807 #ifdef HAVE_WORKING_FORK
808 int x;
809 #endif
810 int res;
811 struct rusage rusage;
812 int status;
814 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
815 ast_replace_sigchld();
817 #ifdef HAVE_WORKING_FORK
818 pid = fork();
819 #else
820 pid = vfork();
821 #endif
823 if (pid == 0) {
824 #ifdef HAVE_WORKING_FORK
825 if (ast_opt_high_priority)
826 ast_set_priority(0);
827 /* Close file descriptors and launch system command */
828 for (x = STDERR_FILENO + 1; x < 4096; x++)
829 close(x);
830 #endif
831 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
832 _exit(1);
833 } else if (pid > 0) {
834 for(;;) {
835 res = wait4(pid, &status, 0, &rusage);
836 if (res > -1) {
837 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
838 break;
839 } else if (errno != EINTR)
840 break;
842 } else {
843 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
844 res = -1;
847 ast_unreplace_sigchld();
848 #else
849 res = -1;
850 #endif
852 return res;
856 * \brief mute or unmute a console from logging
858 void ast_console_toggle_mute(int fd, int silent) {
859 int x;
860 for (x = 0;x < AST_MAX_CONNECTS; x++) {
861 if (fd == consoles[x].fd) {
862 if (consoles[x].mute) {
863 consoles[x].mute = 0;
864 if (!silent)
865 ast_cli(fd, "Console is not muted anymore.\n");
866 } else {
867 consoles[x].mute = 1;
868 if (!silent)
869 ast_cli(fd, "Console is muted.\n");
871 return;
874 ast_cli(fd, "Couldn't find remote console.\n");
878 * \brief log the string to all attached console clients
880 static void ast_network_puts_mutable(const char *string)
882 int x;
883 for (x = 0;x < AST_MAX_CONNECTS; x++) {
884 if (consoles[x].mute)
885 continue;
886 if (consoles[x].fd > -1)
887 fdprint(consoles[x].p[1], string);
892 * \brief log the string to the console, and all attached
893 * console clients
895 void ast_console_puts_mutable(const char *string)
897 fputs(string, stdout);
898 fflush(stdout);
899 ast_network_puts_mutable(string);
903 * \brief write the string to all attached console clients
905 static void ast_network_puts(const char *string)
907 int x;
908 for (x=0; x < AST_MAX_CONNECTS; x++) {
909 if (consoles[x].fd > -1)
910 fdprint(consoles[x].p[1], string);
915 * write the string to the console, and all attached
916 * console clients
918 void ast_console_puts(const char *string)
920 fputs(string, stdout);
921 fflush(stdout);
922 ast_network_puts(string);
925 static void network_verboser(const char *s)
927 ast_network_puts_mutable(s);
930 static pthread_t lthread;
932 static void *netconsole(void *vconsole)
934 struct console *con = vconsole;
935 char hostname[MAXHOSTNAMELEN] = "";
936 char tmp[512];
937 int res;
938 struct pollfd fds[2];
940 if (gethostname(hostname, sizeof(hostname)-1))
941 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
942 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
943 fdprint(con->fd, tmp);
944 for(;;) {
945 fds[0].fd = con->fd;
946 fds[0].events = POLLIN;
947 fds[0].revents = 0;
948 fds[1].fd = con->p[0];
949 fds[1].events = POLLIN;
950 fds[1].revents = 0;
952 res = poll(fds, 2, -1);
953 if (res < 0) {
954 if (errno != EINTR)
955 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
956 continue;
958 if (fds[0].revents) {
959 res = read(con->fd, tmp, sizeof(tmp));
960 if (res < 1) {
961 break;
963 tmp[res] = 0;
964 ast_cli_command_multiple(con->fd, res, tmp);
966 if (fds[1].revents) {
967 res = read(con->p[0], tmp, sizeof(tmp));
968 if (res < 1) {
969 ast_log(LOG_ERROR, "read returned %d\n", res);
970 break;
972 res = write(con->fd, tmp, res);
973 if (res < 1)
974 break;
977 if (option_verbose > 2)
978 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
979 close(con->fd);
980 close(con->p[0]);
981 close(con->p[1]);
982 con->fd = -1;
984 return NULL;
987 static void *listener(void *unused)
989 struct sockaddr_un sunaddr;
990 int s;
991 socklen_t len;
992 int x;
993 int flags;
994 struct pollfd fds[1];
995 pthread_attr_t attr;
996 pthread_attr_init(&attr);
997 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
998 for (;;) {
999 if (ast_socket < 0)
1000 return NULL;
1001 fds[0].fd = ast_socket;
1002 fds[0].events = POLLIN;
1003 s = poll(fds, 1, -1);
1004 pthread_testcancel();
1005 if (s < 0) {
1006 if (errno != EINTR)
1007 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1008 continue;
1010 len = sizeof(sunaddr);
1011 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1012 if (s < 0) {
1013 if (errno != EINTR)
1014 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1015 } else {
1016 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1017 if (consoles[x].fd < 0) {
1018 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1019 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1020 consoles[x].fd = -1;
1021 fdprint(s, "Server failed to create pipe\n");
1022 close(s);
1023 break;
1025 flags = fcntl(consoles[x].p[1], F_GETFL);
1026 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1027 consoles[x].fd = s;
1028 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1029 if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) {
1030 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1031 close(consoles[x].p[0]);
1032 close(consoles[x].p[1]);
1033 consoles[x].fd = -1;
1034 fdprint(s, "Server failed to spawn thread\n");
1035 close(s);
1037 break;
1040 if (x >= AST_MAX_CONNECTS) {
1041 fdprint(s, "No more connections allowed\n");
1042 ast_log(LOG_WARNING, "No more connections allowed\n");
1043 close(s);
1044 } else if (consoles[x].fd > -1) {
1045 if (option_verbose > 2)
1046 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
1050 return NULL;
1053 static int ast_makesocket(void)
1055 struct sockaddr_un sunaddr;
1056 int res;
1057 int x;
1058 uid_t uid = -1;
1059 gid_t gid = -1;
1061 for (x = 0; x < AST_MAX_CONNECTS; x++)
1062 consoles[x].fd = -1;
1063 unlink(ast_config_AST_SOCKET);
1064 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1065 if (ast_socket < 0) {
1066 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1067 return -1;
1069 memset(&sunaddr, 0, sizeof(sunaddr));
1070 sunaddr.sun_family = AF_LOCAL;
1071 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1072 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1073 if (res) {
1074 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1075 close(ast_socket);
1076 ast_socket = -1;
1077 return -1;
1079 res = listen(ast_socket, 2);
1080 if (res < 0) {
1081 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1082 close(ast_socket);
1083 ast_socket = -1;
1084 return -1;
1086 ast_register_verbose(network_verboser);
1087 ast_pthread_create_background(&lthread, NULL, listener, NULL);
1089 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1090 struct passwd *pw;
1091 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
1092 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1093 } else {
1094 uid = pw->pw_uid;
1098 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1099 struct group *grp;
1100 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
1101 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1102 } else {
1103 gid = grp->gr_gid;
1107 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1108 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1110 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1111 int p1;
1112 mode_t p;
1113 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
1114 p = p1;
1115 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1116 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1119 return 0;
1122 static int ast_tryconnect(void)
1124 struct sockaddr_un sunaddr;
1125 int res;
1126 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1127 if (ast_consock < 0) {
1128 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1129 return 0;
1131 memset(&sunaddr, 0, sizeof(sunaddr));
1132 sunaddr.sun_family = AF_LOCAL;
1133 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1134 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1135 if (res) {
1136 close(ast_consock);
1137 ast_consock = -1;
1138 return 0;
1139 } else
1140 return 1;
1143 /*! \brief Urgent handler
1145 Called by soft_hangup to interrupt the poll, read, or other
1146 system call. We don't actually need to do anything though.
1147 Remember: Cannot EVER ast_log from within a signal handler
1149 static void urg_handler(int num)
1151 signal(num, urg_handler);
1152 return;
1155 static void hup_handler(int num)
1157 int a = 0;
1158 if (option_verbose > 1)
1159 printf("Received HUP signal -- Reloading configs\n");
1160 if (restartnow)
1161 execvp(_argv[0], _argv);
1162 sig_flags.need_reload = 1;
1163 if (sig_alert_pipe[1] != -1)
1164 write(sig_alert_pipe[1], &a, sizeof(a));
1165 signal(num, hup_handler);
1168 static void child_handler(int sig)
1170 /* Must not ever ast_log or ast_verbose within signal handler */
1171 int n, status;
1174 * Reap all dead children -- not just one
1176 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1178 if (n == 0 && option_debug)
1179 printf("Huh? Child handler, but nobody there?\n");
1180 signal(sig, child_handler);
1183 /*! \brief Set an X-term or screen title */
1184 static void set_title(char *text)
1186 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1187 fprintf(stdout, "\033]2;%s\007", text);
1190 static void set_icon(char *text)
1192 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1193 fprintf(stdout, "\033]1;%s\007", text);
1196 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1197 else. If your PBX has heavy activity on it, this is a good thing. */
1198 int ast_set_priority(int pri)
1200 struct sched_param sched;
1201 memset(&sched, 0, sizeof(sched));
1202 #ifdef __linux__
1203 if (pri) {
1204 sched.sched_priority = 10;
1205 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1206 ast_log(LOG_WARNING, "Unable to set high priority\n");
1207 return -1;
1208 } else
1209 if (option_verbose)
1210 ast_verbose("Set to realtime thread\n");
1211 } else {
1212 sched.sched_priority = 0;
1213 /* According to the manpage, these parameters can never fail. */
1214 sched_setscheduler(0, SCHED_OTHER, &sched);
1216 #else
1217 if (pri) {
1218 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1219 ast_log(LOG_WARNING, "Unable to set high priority\n");
1220 return -1;
1221 } else
1222 if (option_verbose)
1223 ast_verbose("Set to high priority\n");
1224 } else {
1225 /* According to the manpage, these parameters can never fail. */
1226 setpriority(PRIO_PROCESS, 0, 0);
1228 #endif
1229 return 0;
1232 static void ast_run_atexits(void)
1234 struct ast_atexit *ae;
1235 AST_LIST_LOCK(&atexits);
1236 AST_LIST_TRAVERSE(&atexits, ae, list) {
1237 if (ae->func)
1238 ae->func();
1240 AST_LIST_UNLOCK(&atexits);
1243 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1245 char filename[80] = "";
1246 time_t s,e;
1247 int x;
1248 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1249 ast_cdr_engine_term();
1250 if (safeshutdown) {
1251 shuttingdown = 1;
1252 if (!nice) {
1253 /* Begin shutdown routine, hanging up active channels */
1254 ast_begin_shutdown(1);
1255 if (option_verbose && ast_opt_console)
1256 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1257 time(&s);
1258 for (;;) {
1259 time(&e);
1260 /* Wait up to 15 seconds for all channels to go away */
1261 if ((e - s) > 15)
1262 break;
1263 if (!ast_active_channels())
1264 break;
1265 if (!shuttingdown)
1266 break;
1267 /* Sleep 1/10 of a second */
1268 usleep(100000);
1270 } else {
1271 if (nice < 2)
1272 ast_begin_shutdown(0);
1273 if (option_verbose && ast_opt_console)
1274 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1275 for (;;) {
1276 if (!ast_active_channels())
1277 break;
1278 if (!shuttingdown)
1279 break;
1280 sleep(1);
1284 if (!shuttingdown) {
1285 if (option_verbose && ast_opt_console)
1286 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1287 return;
1290 if (nice)
1291 ast_module_shutdown();
1293 if (ast_opt_console || ast_opt_remote) {
1294 if (getenv("HOME"))
1295 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1296 if (!ast_strlen_zero(filename))
1297 ast_el_write_history(filename);
1298 if (el != NULL)
1299 el_end(el);
1300 if (el_hist != NULL)
1301 history_end(el_hist);
1303 if (option_verbose)
1304 ast_verbose("Executing last minute cleanups\n");
1305 ast_run_atexits();
1306 /* Called on exit */
1307 if (option_verbose && ast_opt_console)
1308 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1309 if (option_debug)
1310 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1311 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1312 if (ast_socket > -1) {
1313 pthread_cancel(lthread);
1314 close(ast_socket);
1315 ast_socket = -1;
1316 unlink(ast_config_AST_SOCKET);
1318 if (ast_consock > -1)
1319 close(ast_consock);
1320 if (!ast_opt_remote)
1321 unlink(ast_config_AST_PID);
1322 printf(term_quit());
1323 if (restart) {
1324 if (option_verbose || ast_opt_console)
1325 ast_verbose("Preparing for Asterisk restart...\n");
1326 /* Mark all FD's for closing on exec */
1327 for (x=3; x < 32768; x++) {
1328 fcntl(x, F_SETFD, FD_CLOEXEC);
1330 if (option_verbose || ast_opt_console)
1331 ast_verbose("Asterisk is now restarting...\n");
1332 restartnow = 1;
1334 /* close logger */
1335 close_logger();
1337 /* If there is a consolethread running send it a SIGHUP
1338 so it can execvp, otherwise we can do it ourselves */
1339 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1340 pthread_kill(consolethread, SIGHUP);
1341 /* Give the signal handler some time to complete */
1342 sleep(2);
1343 } else
1344 execvp(_argv[0], _argv);
1346 } else {
1347 /* close logger */
1348 close_logger();
1350 exit(0);
1353 static void __quit_handler(int num)
1355 int a = 0;
1356 sig_flags.need_quit = 1;
1357 if (sig_alert_pipe[1] != -1)
1358 write(sig_alert_pipe[1], &a, sizeof(a));
1359 /* There is no need to restore the signal handler here, since the app
1360 * is going to exit */
1363 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1365 const char *c;
1367 /* Check for verboser preamble */
1368 if (*s == 127) {
1369 s++;
1372 if (!strncmp(s, cmp, strlen(cmp))) {
1373 c = s + strlen(cmp);
1374 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1375 return c;
1377 return NULL;
1380 static void console_verboser(const char *s)
1382 char tmp[80];
1383 const char *c = NULL;
1385 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1386 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1387 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1388 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1389 fputs(tmp, stdout);
1390 fputs(c, stdout);
1391 } else {
1392 if (*s == 127) {
1393 s++;
1395 fputs(s, stdout);
1398 fflush(stdout);
1400 /* Wake up a poll()ing console */
1401 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1402 pthread_kill(consolethread, SIGURG);
1405 static int ast_all_zeros(char *s)
1407 while (*s) {
1408 if (*s > 32)
1409 return 0;
1410 s++;
1412 return 1;
1415 static void consolehandler(char *s)
1417 printf(term_end());
1418 fflush(stdout);
1420 /* Called when readline data is available */
1421 if (!ast_all_zeros(s))
1422 ast_el_add_history(s);
1423 /* The real handler for bang */
1424 if (s[0] == '!') {
1425 if (s[1])
1426 ast_safe_system(s+1);
1427 else
1428 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1429 } else
1430 ast_cli_command(STDOUT_FILENO, s);
1433 static int remoteconsolehandler(char *s)
1435 int ret = 0;
1437 /* Called when readline data is available */
1438 if (!ast_all_zeros(s))
1439 ast_el_add_history(s);
1440 /* The real handler for bang */
1441 if (s[0] == '!') {
1442 if (s[1])
1443 ast_safe_system(s+1);
1444 else
1445 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1446 ret = 1;
1448 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1449 (s[4] == '\0' || isspace(s[4]))) {
1450 quit_handler(0, 0, 0, 0);
1451 ret = 1;
1454 return ret;
1457 static char abort_halt_help[] =
1458 "Usage: abort shutdown\n"
1459 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1460 " call operations.\n";
1462 static char shutdown_now_help[] =
1463 "Usage: stop now\n"
1464 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1466 static char shutdown_gracefully_help[] =
1467 "Usage: stop gracefully\n"
1468 " Causes Asterisk to not accept new calls, and exit when all\n"
1469 " active calls have terminated normally.\n";
1471 static char shutdown_when_convenient_help[] =
1472 "Usage: stop when convenient\n"
1473 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1475 static char restart_now_help[] =
1476 "Usage: restart now\n"
1477 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1478 " restart.\n";
1480 static char restart_gracefully_help[] =
1481 "Usage: restart gracefully\n"
1482 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1483 " restart when all active calls have ended.\n";
1485 static char restart_when_convenient_help[] =
1486 "Usage: restart when convenient\n"
1487 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1489 static char bang_help[] =
1490 "Usage: !<command>\n"
1491 " Executes a given shell command\n";
1493 static char show_warranty_help[] =
1494 "Usage: core show warranty\n"
1495 " Shows the warranty (if any) for this copy of Asterisk.\n";
1497 static char show_license_help[] =
1498 "Usage: core show license\n"
1499 " Shows the license(s) for this copy of Asterisk.\n";
1501 static char version_help[] =
1502 "Usage: core show version\n"
1503 " Shows Asterisk version information.\n";
1505 static int handle_version_deprecated(int fd, int argc, char *argv[])
1507 if (argc != 2)
1508 return RESULT_SHOWUSAGE;
1509 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1510 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1511 ast_build_machine, ast_build_os, ast_build_date);
1512 return RESULT_SUCCESS;
1515 static int handle_version(int fd, int argc, char *argv[])
1517 if (argc != 3)
1518 return RESULT_SHOWUSAGE;
1519 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1520 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1521 ast_build_machine, ast_build_os, ast_build_date);
1522 return RESULT_SUCCESS;
1525 #if 0
1526 static int handle_quit(int fd, int argc, char *argv[])
1528 if (argc != 1)
1529 return RESULT_SHOWUSAGE;
1530 quit_handler(0, 0, 1, 0);
1531 return RESULT_SUCCESS;
1533 #endif
1535 static int handle_shutdown_now(int fd, int argc, char *argv[])
1537 if (argc != 2)
1538 return RESULT_SHOWUSAGE;
1539 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1540 return RESULT_SUCCESS;
1543 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1545 if (argc != 2)
1546 return RESULT_SHOWUSAGE;
1547 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1548 return RESULT_SUCCESS;
1551 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1553 if (argc != 3)
1554 return RESULT_SHOWUSAGE;
1555 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1556 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1557 return RESULT_SUCCESS;
1560 static int handle_restart_now(int fd, int argc, char *argv[])
1562 if (argc != 2)
1563 return RESULT_SHOWUSAGE;
1564 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1565 return RESULT_SUCCESS;
1568 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1570 if (argc != 2)
1571 return RESULT_SHOWUSAGE;
1572 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1573 return RESULT_SUCCESS;
1576 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1578 if (argc != 3)
1579 return RESULT_SHOWUSAGE;
1580 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1581 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1582 return RESULT_SUCCESS;
1585 static int handle_abort_halt(int fd, int argc, char *argv[])
1587 if (argc != 2)
1588 return RESULT_SHOWUSAGE;
1589 ast_cancel_shutdown();
1590 shuttingdown = 0;
1591 return RESULT_SUCCESS;
1594 static int handle_bang(int fd, int argc, char *argv[])
1596 return RESULT_SUCCESS;
1598 static const char *warranty_lines[] = {
1599 "\n",
1600 " NO WARRANTY\n",
1601 "\n",
1602 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1603 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1604 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1605 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1606 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1607 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1608 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1609 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1610 "REPAIR OR CORRECTION.\n",
1611 "\n",
1612 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1613 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1614 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1615 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1616 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1617 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1618 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1619 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1620 "POSSIBILITY OF SUCH DAMAGES.\n",
1623 static int show_warranty(int fd, int argc, char *argv[])
1625 int x;
1627 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1628 ast_cli(fd, (char *) warranty_lines[x]);
1630 return RESULT_SUCCESS;
1633 static const char *license_lines[] = {
1634 "\n",
1635 "This program is free software; you can redistribute it and/or modify\n",
1636 "it under the terms of the GNU General Public License version 2 as\n",
1637 "published by the Free Software Foundation.\n",
1638 "\n",
1639 "This program also contains components licensed under other licenses.\n",
1640 "They include:\n",
1641 "\n",
1642 "This program is distributed in the hope that it will be useful,\n",
1643 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1644 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1645 "GNU General Public License for more details.\n",
1646 "\n",
1647 "You should have received a copy of the GNU General Public License\n",
1648 "along with this program; if not, write to the Free Software\n",
1649 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1652 static int show_license(int fd, int argc, char *argv[])
1654 int x;
1656 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1657 ast_cli(fd, (char *) license_lines[x]);
1659 return RESULT_SUCCESS;
1662 #define ASTERISK_PROMPT "*CLI> "
1664 #define ASTERISK_PROMPT2 "%s*CLI> "
1666 static struct ast_cli_entry cli_show_version_deprecated = {
1667 { "show", "version", NULL },
1668 handle_version_deprecated, "Display version info",
1669 version_help };
1671 #if !defined(LOW_MEMORY)
1672 static struct ast_cli_entry cli_show_version_files_deprecated = {
1673 { "show", "version", "files", NULL },
1674 handle_show_version_files_deprecated, NULL,
1675 NULL, complete_show_version_files_deprecated };
1677 static struct ast_cli_entry cli_show_profile_deprecated = {
1678 { "show", "profile", NULL },
1679 handle_show_profile_deprecated, NULL,
1680 NULL };
1682 static struct ast_cli_entry cli_clear_profile_deprecated = {
1683 { "clear", "profile", NULL },
1684 handle_show_profile_deprecated, NULL,
1685 NULL };
1686 #endif /* ! LOW_MEMORY */
1688 static struct ast_cli_entry cli_asterisk[] = {
1689 { { "abort", "halt", NULL },
1690 handle_abort_halt, "Cancel a running halt",
1691 abort_halt_help },
1693 { { "stop", "now", NULL },
1694 handle_shutdown_now, "Shut down Asterisk immediately",
1695 shutdown_now_help },
1697 { { "stop", "gracefully", NULL },
1698 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1699 shutdown_gracefully_help },
1701 { { "stop", "when", "convenient", NULL },
1702 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1703 shutdown_when_convenient_help },
1705 { { "restart", "now", NULL },
1706 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1708 { { "restart", "gracefully", NULL },
1709 handle_restart_gracefully, "Restart Asterisk gracefully",
1710 restart_gracefully_help },
1712 { { "restart", "when", "convenient", NULL },
1713 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1714 restart_when_convenient_help },
1716 { { "core", "show", "warranty", NULL },
1717 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1718 show_warranty_help },
1720 { { "core", "show", "license", NULL },
1721 show_license, "Show the license(s) for this copy of Asterisk",
1722 show_license_help },
1724 { { "core", "show", "version", NULL },
1725 handle_version, "Display version info",
1726 version_help, NULL, &cli_show_version_deprecated },
1728 { { "!", NULL },
1729 handle_bang, "Execute a shell command",
1730 bang_help },
1732 #if !defined(LOW_MEMORY)
1733 { { "core", "show", "file", "version", NULL },
1734 handle_show_version_files, "List versions of files used to build Asterisk",
1735 show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
1737 { { "core", "show", "threads", NULL },
1738 handle_show_threads, "Show running threads",
1739 show_threads_help },
1741 { { "core", "show", "profile", NULL },
1742 handle_show_profile, "Display profiling info",
1743 NULL, NULL, &cli_show_profile_deprecated },
1745 { { "core", "clear", "profile", NULL },
1746 handle_show_profile, "Clear profiling info",
1747 NULL, NULL, &cli_clear_profile_deprecated },
1748 #endif /* ! LOW_MEMORY */
1751 static int ast_el_read_char(EditLine *el, char *cp)
1753 int num_read = 0;
1754 int lastpos = 0;
1755 struct pollfd fds[2];
1756 int res;
1757 int max;
1758 #define EL_BUF_SIZE 512
1759 char buf[EL_BUF_SIZE];
1761 for (;;) {
1762 max = 1;
1763 fds[0].fd = ast_consock;
1764 fds[0].events = POLLIN;
1765 if (!ast_opt_exec) {
1766 fds[1].fd = STDIN_FILENO;
1767 fds[1].events = POLLIN;
1768 max++;
1770 res = poll(fds, max, -1);
1771 if (res < 0) {
1772 if (errno == EINTR)
1773 continue;
1774 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1775 break;
1778 if (!ast_opt_exec && fds[1].revents) {
1779 num_read = read(STDIN_FILENO, cp, 1);
1780 if (num_read < 1) {
1781 break;
1782 } else
1783 return (num_read);
1785 if (fds[0].revents) {
1786 char *tmp;
1787 res = read(ast_consock, buf, sizeof(buf) - 1);
1788 /* if the remote side disappears exit */
1789 if (res < 1) {
1790 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1791 if (!ast_opt_reconnect) {
1792 quit_handler(0, 0, 0, 0);
1793 } else {
1794 int tries;
1795 int reconnects_per_second = 20;
1796 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1797 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1798 if (ast_tryconnect()) {
1799 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1800 printf(term_quit());
1801 WELCOME_MESSAGE;
1802 if (!ast_opt_mute)
1803 fdsend(ast_consock, "logger mute silent");
1804 else
1805 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
1806 break;
1807 } else {
1808 usleep(1000000 / reconnects_per_second);
1811 if (tries >= 30 * reconnects_per_second) {
1812 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1813 quit_handler(0, 0, 0, 0);
1818 buf[res] = '\0';
1820 /* Strip preamble from asynchronous events, too */
1821 for (tmp = buf; *tmp; tmp++) {
1822 if (*tmp == 127) {
1823 memmove(tmp, tmp + 1, strlen(tmp));
1824 tmp--;
1828 /* Write over the CLI prompt */
1829 if (!ast_opt_exec && !lastpos)
1830 write(STDOUT_FILENO, "\r", 1);
1831 write(STDOUT_FILENO, buf, res);
1832 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
1833 *cp = CC_REFRESH;
1834 return(1);
1835 } else {
1836 lastpos = 1;
1841 *cp = '\0';
1842 return (0);
1845 static char *cli_prompt(EditLine *el)
1847 static char prompt[200];
1848 char *pfmt;
1849 int color_used = 0;
1850 char term_code[20];
1852 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1853 char *t = pfmt, *p = prompt;
1854 memset(prompt, 0, sizeof(prompt));
1855 while (*t != '\0' && *p < sizeof(prompt)) {
1856 if (*t == '%') {
1857 char hostname[MAXHOSTNAMELEN]="";
1858 int i;
1859 time_t ts;
1860 struct tm tm;
1861 #ifdef linux
1862 FILE *LOADAVG;
1863 #endif
1864 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1866 t++;
1867 switch (*t) {
1868 case 'C': /* color */
1869 t++;
1870 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1871 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1872 t += i - 1;
1873 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1874 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1875 t += i - 1;
1878 /* If the color has been reset correctly, then there's no need to reset it later */
1879 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1880 color_used = 0;
1881 } else {
1882 color_used = 1;
1884 break;
1885 case 'd': /* date */
1886 memset(&tm, 0, sizeof(tm));
1887 time(&ts);
1888 if (ast_localtime(&ts, &tm, NULL)) {
1889 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1891 break;
1892 case 'h': /* hostname */
1893 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1894 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1895 } else {
1896 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1898 break;
1899 case 'H': /* short hostname */
1900 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1901 for (i = 0; i < sizeof(hostname); i++) {
1902 if (hostname[i] == '.') {
1903 hostname[i] = '\0';
1904 break;
1907 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1908 } else {
1909 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1911 break;
1912 #ifdef linux
1913 case 'l': /* load avg */
1914 t++;
1915 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1916 float avg1, avg2, avg3;
1917 int actproc, totproc, npid, which;
1918 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1919 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1920 if (sscanf(t, "%d", &which) == 1) {
1921 switch (which) {
1922 case 1:
1923 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1924 break;
1925 case 2:
1926 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1927 break;
1928 case 3:
1929 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1930 break;
1931 case 4:
1932 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1933 break;
1934 case 5:
1935 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1936 break;
1940 break;
1941 #endif
1942 case 's': /* Asterisk system name (from asterisk.conf) */
1943 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1944 break;
1945 case 't': /* time */
1946 memset(&tm, 0, sizeof(tm));
1947 time(&ts);
1948 if (ast_localtime(&ts, &tm, NULL)) {
1949 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1951 break;
1952 case '#': /* process console or remote? */
1953 if (!ast_opt_remote) {
1954 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1955 } else {
1956 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1958 break;
1959 case '%': /* literal % */
1960 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1961 break;
1962 case '\0': /* % is last character - prevent bug */
1963 t--;
1964 break;
1966 while (*p != '\0') {
1967 p++;
1969 t++;
1970 } else {
1971 *p = *t;
1972 p++;
1973 t++;
1976 if (color_used) {
1977 /* Force colors back to normal at end */
1978 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1979 if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
1980 ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
1981 } else {
1982 /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
1983 strncat(p, term_code, sizeof(term_code));
1986 } else if (remotehostname)
1987 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1988 else
1989 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1991 return(prompt);
1994 static char **ast_el_strtoarr(char *buf)
1996 char **match_list = NULL, *retstr;
1997 size_t match_list_len;
1998 int matches = 0;
2000 match_list_len = 1;
2001 while ( (retstr = strsep(&buf, " ")) != NULL) {
2003 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2004 break;
2005 if (matches + 1 >= match_list_len) {
2006 match_list_len <<= 1;
2007 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2008 /* TODO: Handle memory allocation failure */
2012 match_list[matches++] = strdup(retstr);
2015 if (!match_list)
2016 return (char **) NULL;
2018 if (matches >= match_list_len) {
2019 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2020 /* TODO: Handle memory allocation failure */
2024 match_list[matches] = (char *) NULL;
2026 return match_list;
2029 static int ast_el_sort_compare(const void *i1, const void *i2)
2031 char *s1, *s2;
2033 s1 = ((char **)i1)[0];
2034 s2 = ((char **)i2)[0];
2036 return strcasecmp(s1, s2);
2039 static int ast_cli_display_match_list(char **matches, int len, int max)
2041 int i, idx, limit, count;
2042 int screenwidth = 0;
2043 int numoutput = 0, numoutputline = 0;
2045 screenwidth = ast_get_termcols(STDOUT_FILENO);
2047 /* find out how many entries can be put on one line, with two spaces between strings */
2048 limit = screenwidth / (max + 2);
2049 if (limit == 0)
2050 limit = 1;
2052 /* how many lines of output */
2053 count = len / limit;
2054 if (count * limit < len)
2055 count++;
2057 idx = 1;
2059 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2061 for (; count > 0; count--) {
2062 numoutputline = 0;
2063 for (i=0; i < limit && matches[idx]; i++, idx++) {
2065 /* Don't print dupes */
2066 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2067 i--;
2068 free(matches[idx]);
2069 matches[idx] = NULL;
2070 continue;
2073 numoutput++;
2074 numoutputline++;
2075 fprintf(stdout, "%-*s ", max, matches[idx]);
2076 free(matches[idx]);
2077 matches[idx] = NULL;
2079 if (numoutputline > 0)
2080 fprintf(stdout, "\n");
2083 return numoutput;
2087 static char *cli_complete(EditLine *el, int ch)
2089 int len = 0;
2090 char *ptr;
2091 int nummatches = 0;
2092 char **matches;
2093 int retval = CC_ERROR;
2094 char buf[2048];
2095 int res;
2097 LineInfo *lf = (LineInfo *)el_line(el);
2099 *(char *)lf->cursor = '\0';
2100 ptr = (char *)lf->cursor;
2101 if (ptr) {
2102 while (ptr > lf->buffer) {
2103 if (isspace(*ptr)) {
2104 ptr++;
2105 break;
2107 ptr--;
2111 len = lf->cursor - ptr;
2113 if (ast_opt_remote) {
2114 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2115 fdsend(ast_consock, buf);
2116 res = read(ast_consock, buf, sizeof(buf));
2117 buf[res] = '\0';
2118 nummatches = atoi(buf);
2120 if (nummatches > 0) {
2121 char *mbuf;
2122 int mlen = 0, maxmbuf = 2048;
2123 /* Start with a 2048 byte buffer */
2124 if (!(mbuf = ast_malloc(maxmbuf)))
2125 return (char *)(CC_ERROR);
2126 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2127 fdsend(ast_consock, buf);
2128 res = 0;
2129 mbuf[0] = '\0';
2130 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2131 if (mlen + 1024 > maxmbuf) {
2132 /* Every step increment buffer 1024 bytes */
2133 maxmbuf += 1024;
2134 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2135 return (char *)(CC_ERROR);
2137 /* Only read 1024 bytes at a time */
2138 res = read(ast_consock, mbuf + mlen, 1024);
2139 if (res > 0)
2140 mlen += res;
2142 mbuf[mlen] = '\0';
2144 matches = ast_el_strtoarr(mbuf);
2145 free(mbuf);
2146 } else
2147 matches = (char **) NULL;
2148 } else {
2149 char **p, *oldbuf=NULL;
2150 nummatches = 0;
2151 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2152 for (p = matches; p && *p; p++) {
2153 if (!oldbuf || strcmp(*p,oldbuf))
2154 nummatches++;
2155 oldbuf = *p;
2159 if (matches) {
2160 int i;
2161 int matches_num, maxlen, match_len;
2163 if (matches[0][0] != '\0') {
2164 el_deletestr(el, (int) len);
2165 el_insertstr(el, matches[0]);
2166 retval = CC_REFRESH;
2169 if (nummatches == 1) {
2170 /* Found an exact match */
2171 el_insertstr(el, " ");
2172 retval = CC_REFRESH;
2173 } else {
2174 /* Must be more than one match */
2175 for (i=1, maxlen=0; matches[i]; i++) {
2176 match_len = strlen(matches[i]);
2177 if (match_len > maxlen)
2178 maxlen = match_len;
2180 matches_num = i - 1;
2181 if (matches_num >1) {
2182 fprintf(stdout, "\n");
2183 ast_cli_display_match_list(matches, nummatches, maxlen);
2184 retval = CC_REDISPLAY;
2185 } else {
2186 el_insertstr(el," ");
2187 retval = CC_REFRESH;
2190 for (i = 0; matches[i]; i++)
2191 free(matches[i]);
2192 free(matches);
2195 return (char *)(long)retval;
2198 static int ast_el_initialize(void)
2200 HistEvent ev;
2201 char *editor = getenv("AST_EDITOR");
2203 if (el != NULL)
2204 el_end(el);
2205 if (el_hist != NULL)
2206 history_end(el_hist);
2208 el = el_init("asterisk", stdin, stdout, stderr);
2209 el_set(el, EL_PROMPT, cli_prompt);
2211 el_set(el, EL_EDITMODE, 1);
2212 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2213 el_hist = history_init();
2214 if (!el || !el_hist)
2215 return -1;
2217 /* setup history with 100 entries */
2218 history(el_hist, &ev, H_SETSIZE, 100);
2220 el_set(el, EL_HIST, history, el_hist);
2222 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2223 /* Bind <tab> to command completion */
2224 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2225 /* Bind ? to command completion */
2226 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2227 /* Bind ^D to redisplay */
2228 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2230 return 0;
2233 static int ast_el_add_history(char *buf)
2235 HistEvent ev;
2237 if (el_hist == NULL || el == NULL)
2238 ast_el_initialize();
2239 if (strlen(buf) > 256)
2240 return 0;
2241 return (history(el_hist, &ev, H_ENTER, buf));
2244 static int ast_el_write_history(char *filename)
2246 HistEvent ev;
2248 if (el_hist == NULL || el == NULL)
2249 ast_el_initialize();
2251 return (history(el_hist, &ev, H_SAVE, filename));
2254 static int ast_el_read_history(char *filename)
2256 char buf[256];
2257 FILE *f;
2258 int ret = -1;
2260 if (el_hist == NULL || el == NULL)
2261 ast_el_initialize();
2263 if ((f = fopen(filename, "r")) == NULL)
2264 return ret;
2266 while (!feof(f)) {
2267 fgets(buf, sizeof(buf), f);
2268 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2269 continue;
2270 if (ast_all_zeros(buf))
2271 continue;
2272 if ((ret = ast_el_add_history(buf)) == -1)
2273 break;
2275 fclose(f);
2277 return ret;
2280 static void ast_remotecontrol(char * data)
2282 char buf[80];
2283 int res;
2284 char filename[80] = "";
2285 char *hostname;
2286 char *cpid;
2287 char *version;
2288 int pid;
2289 char tmp[80];
2290 char *stringp = NULL;
2292 char *ebuf;
2293 int num = 0;
2295 read(ast_consock, buf, sizeof(buf));
2296 if (data)
2297 write(ast_consock, data, strlen(data) + 1);
2298 stringp = buf;
2299 hostname = strsep(&stringp, "/");
2300 cpid = strsep(&stringp, "/");
2301 version = strsep(&stringp, "\n");
2302 if (!version)
2303 version = "<Version Unknown>";
2304 stringp = hostname;
2305 strsep(&stringp, ".");
2306 if (cpid)
2307 pid = atoi(cpid);
2308 else
2309 pid = -1;
2310 if (!data) {
2311 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2312 fdsend(ast_consock, tmp);
2313 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2314 fdsend(ast_consock, tmp);
2315 if (!ast_opt_mute)
2316 fdsend(ast_consock, "logger mute silent");
2317 else
2318 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2320 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2321 remotehostname = hostname;
2322 if (getenv("HOME"))
2323 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2324 if (el_hist == NULL || el == NULL)
2325 ast_el_initialize();
2327 el_set(el, EL_GETCFN, ast_el_read_char);
2329 if (!ast_strlen_zero(filename))
2330 ast_el_read_history(filename);
2332 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2333 struct pollfd fds;
2334 fds.fd = ast_consock;
2335 fds.events = POLLIN;
2336 fds.revents = 0;
2337 while (poll(&fds, 1, 500) > 0) {
2338 char buf[512] = "", *curline = buf, *nextline;
2339 int not_written = 1;
2341 if (read(ast_consock, buf, sizeof(buf) - 1) <= 0) {
2342 break;
2345 do {
2346 if ((nextline = strchr(curline, '\n'))) {
2347 nextline++;
2348 } else {
2349 nextline = strchr(curline, '\0');
2352 /* Skip verbose lines */
2353 if (*curline != 127) {
2354 not_written = 0;
2355 write(STDOUT_FILENO, curline, nextline - curline);
2357 curline = nextline;
2358 } while (!ast_strlen_zero(curline));
2360 /* No non-verbose output in 500ms */
2361 if (not_written) {
2362 break;
2365 return;
2367 for (;;) {
2368 ebuf = (char *)el_gets(el, &num);
2370 if (!ebuf && write(1, "", 1) < 0)
2371 break;
2373 if (!ast_strlen_zero(ebuf)) {
2374 if (ebuf[strlen(ebuf)-1] == '\n')
2375 ebuf[strlen(ebuf)-1] = '\0';
2376 if (!remoteconsolehandler(ebuf)) {
2377 /* Strip preamble from output */
2378 char *tmp;
2379 for (tmp = ebuf; *tmp; tmp++) {
2380 if (*tmp == 127) {
2381 memmove(tmp, tmp + 1, strlen(tmp));
2382 tmp--;
2385 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2386 if (res < 1) {
2387 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2388 break;
2393 printf("\nDisconnected from Asterisk server\n");
2396 static int show_version(void)
2398 printf("Asterisk " ASTERISK_VERSION "\n");
2399 return 0;
2402 static int show_cli_help(void) {
2403 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2008, Digium, Inc. and others.\n");
2404 printf("Usage: asterisk [OPTIONS]\n");
2405 printf("Valid Options:\n");
2406 printf(" -V Display version number and exit\n");
2407 printf(" -C <configfile> Use an alternate configuration file\n");
2408 printf(" -G <group> Run as a group other than the caller\n");
2409 printf(" -U <user> Run as a user other than the caller\n");
2410 printf(" -c Provide console CLI\n");
2411 printf(" -d Enable extra debugging\n");
2412 #if HAVE_WORKING_FORK
2413 printf(" -f Do not fork\n");
2414 printf(" -F Always fork\n");
2415 #endif
2416 printf(" -g Dump core in case of a crash\n");
2417 printf(" -h This help screen\n");
2418 printf(" -i Initialize crypto keys at startup\n");
2419 printf(" -I Enable internal timing if %s timer is available\n", dahdi_chan_name);
2420 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2421 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2422 printf(" -m Mute debugging and console output on the console\n");
2423 printf(" -n Disable console colorization\n");
2424 printf(" -p Run as pseudo-realtime thread\n");
2425 printf(" -q Quiet mode (suppress output)\n");
2426 printf(" -r Connect to Asterisk on this machine\n");
2427 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
2428 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
2429 printf(" belong after they are done\n");
2430 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2431 printf(" of output to the CLI\n");
2432 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2433 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2434 printf("\n");
2435 return 0;
2438 static void ast_readconfig(void)
2440 struct ast_config *cfg;
2441 struct ast_variable *v;
2442 char *config = AST_CONFIG_FILE;
2444 if (ast_opt_override_config) {
2445 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2446 if (!cfg)
2447 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2448 } else {
2449 cfg = ast_config_load(config);
2452 /* init with buildtime config */
2453 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2454 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2455 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2456 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2457 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2458 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2459 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2460 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2461 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2462 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2463 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2464 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2465 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2467 /* no asterisk.conf? no problem, use buildtime config! */
2468 if (!cfg) {
2469 return;
2472 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2473 if (!strcasecmp(v->name, "astctlpermissions")) {
2474 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2475 } else if (!strcasecmp(v->name, "astctlowner")) {
2476 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2477 } else if (!strcasecmp(v->name, "astctlgroup")) {
2478 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2479 } else if (!strcasecmp(v->name, "astctl")) {
2480 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2484 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2485 if (!strcasecmp(v->name, "astetcdir")) {
2486 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2487 } else if (!strcasecmp(v->name, "astspooldir")) {
2488 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2489 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2490 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2491 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2492 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2493 } else if (!strcasecmp(v->name, "astdatadir")) {
2494 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2495 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2496 } else if (!strcasecmp(v->name, "astlogdir")) {
2497 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2498 } else if (!strcasecmp(v->name, "astagidir")) {
2499 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2500 } else if (!strcasecmp(v->name, "astrundir")) {
2501 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2502 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2503 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2504 } else if (!strcasecmp(v->name, "astmoddir")) {
2505 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2509 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2510 /* verbose level (-v at startup) */
2511 if (!strcasecmp(v->name, "verbose")) {
2512 option_verbose = atoi(v->value);
2513 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2514 } else if (!strcasecmp(v->name, "timestamp")) {
2515 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2516 /* whether or not to support #exec in config files */
2517 } else if (!strcasecmp(v->name, "execincludes")) {
2518 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2519 /* debug level (-d at startup) */
2520 } else if (!strcasecmp(v->name, "debug")) {
2521 option_debug = 0;
2522 if (sscanf(v->value, "%d", &option_debug) != 1) {
2523 option_debug = ast_true(v->value);
2525 #if HAVE_WORKING_FORK
2526 /* Disable forking (-f at startup) */
2527 } else if (!strcasecmp(v->name, "nofork")) {
2528 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2529 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2530 } else if (!strcasecmp(v->name, "alwaysfork")) {
2531 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2532 #endif
2533 /* Run quietly (-q at startup ) */
2534 } else if (!strcasecmp(v->name, "quiet")) {
2535 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2536 /* Run as console (-c at startup, implies nofork) */
2537 } else if (!strcasecmp(v->name, "console")) {
2538 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2539 /* Run with high priority if the O/S permits (-p at startup) */
2540 } else if (!strcasecmp(v->name, "highpriority")) {
2541 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2542 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2543 } else if (!strcasecmp(v->name, "initcrypto")) {
2544 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2545 /* Disable ANSI colors for console (-c at startup) */
2546 } else if (!strcasecmp(v->name, "nocolor")) {
2547 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2548 /* Disable some usage warnings for picky people :p */
2549 } else if (!strcasecmp(v->name, "dontwarn")) {
2550 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2551 /* Dump core in case of crash (-g) */
2552 } else if (!strcasecmp(v->name, "dumpcore")) {
2553 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2554 /* Cache recorded sound files to another directory during recording */
2555 } else if (!strcasecmp(v->name, "cache_record_files")) {
2556 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2557 /* Specify cache directory */
2558 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2559 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2560 /* Build transcode paths via SLINEAR, instead of directly */
2561 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2562 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2563 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2564 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2565 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2566 /* Enable internal timing */
2567 } else if (!strcasecmp(v->name, "internal_timing")) {
2568 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2569 } else if (!strcasecmp(v->name, "maxcalls")) {
2570 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2571 option_maxcalls = 0;
2573 } else if (!strcasecmp(v->name, "maxload")) {
2574 double test[1];
2576 if (getloadavg(test, 1) == -1) {
2577 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2578 option_maxload = 0.0;
2579 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2580 option_maxload = 0.0;
2582 /* What user to run as */
2583 } else if (!strcasecmp(v->name, "runuser")) {
2584 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2585 /* What group to run as */
2586 } else if (!strcasecmp(v->name, "rungroup")) {
2587 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2588 } else if (!strcasecmp(v->name, "systemname")) {
2589 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2590 } else if (!strcasecmp(v->name, "languageprefix")) {
2591 ast_language_is_prefix = ast_true(v->value);
2592 } else if (!strcasecmp(v->name, "dahdichanname")) {
2593 #ifdef HAVE_ZAPTEL
2594 if (ast_true(v->value)) {
2595 strcpy(_dahdi_chan_name, "DAHDI");
2596 dahdi_chan_mode = DAHDI_PLUS_ZAP;
2598 #else
2599 if (ast_false(v->value)) {
2600 strcpy(_dahdi_chan_name, "Zap");
2601 dahdi_chan_mode = ZAP_ONLY_MODE;
2603 #endif
2606 ast_config_destroy(cfg);
2609 static void *monitor_sig_flags(void *unused)
2611 for (;;) {
2612 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2613 int a;
2614 poll(&p, 1, -1);
2615 if (sig_flags.need_reload) {
2616 sig_flags.need_reload = 0;
2617 ast_module_reload(NULL);
2619 if (sig_flags.need_quit) {
2620 sig_flags.need_quit = 0;
2621 quit_handler(0, 0, 1, 0);
2623 read(sig_alert_pipe[0], &a, sizeof(a));
2626 return NULL;
2629 int main(int argc, char *argv[])
2631 int c;
2632 char filename[80] = "";
2633 char hostname[MAXHOSTNAMELEN] = "";
2634 char tmp[80];
2635 char * xarg = NULL;
2636 int x;
2637 FILE *f;
2638 sigset_t sigs;
2639 int num;
2640 int isroot = 1;
2641 char *buf;
2642 char *runuser = NULL, *rungroup = NULL;
2644 /* Remember original args for restart */
2645 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2646 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2647 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2649 for (x=0; x<argc; x++)
2650 _argv[x] = argv[x];
2651 _argv[x] = NULL;
2653 if (geteuid() != 0)
2654 isroot = 0;
2656 /* if the progname is rasterisk consider it a remote console */
2657 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2658 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2660 if (gethostname(hostname, sizeof(hostname)-1))
2661 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2662 ast_mainpid = getpid();
2663 ast_ulaw_init();
2664 ast_alaw_init();
2665 callerid_init();
2666 ast_builtins_init();
2667 ast_utils_init();
2668 tdd_init();
2670 if (getenv("HOME"))
2671 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2672 /* Check for options */
2673 while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2674 switch (c) {
2675 #if HAVE_WORKING_FORK
2676 case 'F':
2677 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2678 break;
2679 case 'f':
2680 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2681 break;
2682 #endif
2683 case 'd':
2684 option_debug++;
2685 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2686 break;
2687 case 'c':
2688 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2689 break;
2690 case 'n':
2691 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2692 break;
2693 case 'r':
2694 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2695 break;
2696 case 'R':
2697 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2698 break;
2699 case 'p':
2700 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2701 break;
2702 case 'v':
2703 option_verbose++;
2704 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2705 break;
2706 case 'm':
2707 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2708 break;
2709 case 'M':
2710 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2711 option_maxcalls = 0;
2712 break;
2713 case 'L':
2714 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2715 option_maxload = 0.0;
2716 break;
2717 case 'q':
2718 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2719 break;
2720 case 't':
2721 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2722 break;
2723 case 'T':
2724 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2725 break;
2726 case 'x':
2727 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2728 xarg = ast_strdupa(optarg);
2729 break;
2730 case 'C':
2731 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2732 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2733 break;
2734 case 'I':
2735 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2736 break;
2737 case 'i':
2738 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2739 break;
2740 case 'g':
2741 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2742 break;
2743 case 'h':
2744 show_cli_help();
2745 exit(0);
2746 case 'V':
2747 show_version();
2748 exit(0);
2749 case 'U':
2750 runuser = ast_strdupa(optarg);
2751 break;
2752 case 'G':
2753 rungroup = ast_strdupa(optarg);
2754 break;
2755 case '?':
2756 exit(1);
2760 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2761 ast_register_verbose(console_verboser);
2762 WELCOME_MESSAGE;
2765 if (ast_opt_console && !option_verbose)
2766 ast_verbose("[ Booting...\n");
2768 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2769 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2770 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2773 /* For remote connections, change the name of the remote connection.
2774 * We do this for the benefit of init scripts (which need to know if/when
2775 * the main asterisk process has died yet). */
2776 if (ast_opt_remote) {
2777 strcpy(argv[0], "rasterisk");
2778 for (x = 1; x < argc; x++) {
2779 argv[x] = argv[0] + 10;
2783 if (ast_opt_console && !option_verbose)
2784 ast_verbose("[ Reading Master Configuration ]\n");
2785 ast_readconfig();
2787 if (ast_opt_dump_core) {
2788 struct rlimit l;
2789 memset(&l, 0, sizeof(l));
2790 l.rlim_cur = RLIM_INFINITY;
2791 l.rlim_max = RLIM_INFINITY;
2792 if (setrlimit(RLIMIT_CORE, &l)) {
2793 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2797 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2798 rungroup = ast_config_AST_RUN_GROUP;
2799 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2800 runuser = ast_config_AST_RUN_USER;
2802 #ifndef __CYGWIN__
2804 if (isroot)
2805 ast_set_priority(ast_opt_high_priority);
2807 if (isroot && rungroup) {
2808 struct group *gr;
2809 gr = getgrnam(rungroup);
2810 if (!gr) {
2811 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2812 exit(1);
2814 if (setgid(gr->gr_gid)) {
2815 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2816 exit(1);
2818 if (setgroups(0, NULL)) {
2819 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2820 exit(1);
2822 if (option_verbose)
2823 ast_verbose("Running as group '%s'\n", rungroup);
2826 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
2827 #ifdef HAVE_CAP
2828 int has_cap = 1;
2829 #endif /* HAVE_CAP */
2830 struct passwd *pw;
2831 pw = getpwnam(runuser);
2832 if (!pw) {
2833 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2834 exit(1);
2836 #ifdef HAVE_CAP
2837 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
2838 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
2839 has_cap = 0;
2841 #endif /* HAVE_CAP */
2842 if (!isroot && pw->pw_uid != geteuid()) {
2843 ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
2844 exit(1);
2846 if (!rungroup) {
2847 if (setgid(pw->pw_gid)) {
2848 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2849 exit(1);
2851 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
2852 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2853 exit(1);
2856 if (setuid(pw->pw_uid)) {
2857 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2858 exit(1);
2860 if (option_verbose)
2861 ast_verbose("Running as user '%s'\n", runuser);
2862 #ifdef HAVE_CAP
2863 if (has_cap) {
2864 cap_t cap;
2866 cap = cap_from_text("cap_net_admin=ep");
2868 if (cap_set_proc(cap))
2869 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
2871 if (cap_free(cap))
2872 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
2874 #endif /* HAVE_CAP */
2877 #endif /* __CYGWIN__ */
2879 #ifdef linux
2880 if (geteuid() && ast_opt_dump_core) {
2881 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2882 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2885 #endif
2887 ast_term_init();
2888 printf(term_end());
2889 fflush(stdout);
2891 if (ast_opt_console && !option_verbose)
2892 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2893 /* custom config setup */
2894 register_config_cli();
2895 read_config_maps();
2897 if (ast_opt_console) {
2898 if (el_hist == NULL || el == NULL)
2899 ast_el_initialize();
2901 if (!ast_strlen_zero(filename))
2902 ast_el_read_history(filename);
2905 if (ast_tryconnect()) {
2906 /* One is already running */
2907 if (ast_opt_remote) {
2908 if (ast_opt_exec) {
2909 ast_remotecontrol(xarg);
2910 quit_handler(0, 0, 0, 0);
2911 exit(0);
2913 printf(term_quit());
2914 ast_remotecontrol(NULL);
2915 quit_handler(0, 0, 0, 0);
2916 exit(0);
2917 } else {
2918 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2919 printf(term_quit());
2920 exit(1);
2922 } else if (ast_opt_remote || ast_opt_exec) {
2923 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2924 printf(term_quit());
2925 exit(1);
2927 /* Blindly write pid file since we couldn't connect */
2928 unlink(ast_config_AST_PID);
2929 f = fopen(ast_config_AST_PID, "w");
2930 if (f) {
2931 fprintf(f, "%ld\n", (long)getpid());
2932 fclose(f);
2933 } else
2934 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2936 #if HAVE_WORKING_FORK
2937 if (ast_opt_always_fork || !ast_opt_no_fork) {
2938 #ifndef HAVE_SBIN_LAUNCHD
2939 daemon(1, 0);
2940 ast_mainpid = getpid();
2941 /* Blindly re-write pid file since we are forking */
2942 unlink(ast_config_AST_PID);
2943 f = fopen(ast_config_AST_PID, "w");
2944 if (f) {
2945 fprintf(f, "%ld\n", (long)ast_mainpid);
2946 fclose(f);
2947 } else
2948 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2949 #else
2950 ast_log(LOG_WARNING, "Mac OS X detected. Use '/sbin/launchd -d' to launch with the nofork option.\n");
2951 #endif
2953 #endif
2955 /* Test recursive mutex locking. */
2956 if (test_for_thread_safety())
2957 ast_verbose("Warning! Asterisk is not thread safe.\n");
2959 ast_makesocket();
2960 sigemptyset(&sigs);
2961 sigaddset(&sigs, SIGHUP);
2962 sigaddset(&sigs, SIGTERM);
2963 sigaddset(&sigs, SIGINT);
2964 sigaddset(&sigs, SIGPIPE);
2965 sigaddset(&sigs, SIGWINCH);
2966 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2967 signal(SIGURG, urg_handler);
2968 signal(SIGINT, __quit_handler);
2969 signal(SIGTERM, __quit_handler);
2970 signal(SIGHUP, hup_handler);
2971 signal(SIGCHLD, child_handler);
2972 signal(SIGPIPE, SIG_IGN);
2974 /* ensure that the random number generators are seeded with a different value every time
2975 Asterisk is started
2977 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2978 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2980 if (init_logger()) {
2981 printf(term_quit());
2982 exit(1);
2985 dahdi_chan_name = _dahdi_chan_name;
2987 #ifdef HAVE_ZAPTEL
2989 int fd;
2990 int x = 160;
2991 fd = open("/dev/zap/timer", O_RDWR);
2992 if (fd >= 0) {
2993 if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
2994 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);
2995 exit(1);
2997 if ((x = ast_wait_for_input(fd, 300)) < 0) {
2998 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");
2999 exit(1);
3001 if (!x) {
3002 const char zaptel_timer_error[] = {
3003 "Asterisk has detected a problem with your Zaptel configuration and will shutdown for your protection. You have options:"
3004 "\n\t1. You only have to compile Zaptel support into Asterisk if you need it. One option is to recompile without Zaptel support."
3005 "\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."
3006 "\n\t3. If you need Zaptel services, you must correctly configure Zaptel."
3008 ast_log(LOG_ERROR, "%s\n", zaptel_timer_error);
3009 exit(1);
3011 close(fd);
3014 #elif defined(HAVE_DAHDI)
3016 int fd;
3017 int x = 160;
3018 fd = open("/dev/dahdi/timer", O_RDWR);
3019 if (fd >= 0) {
3020 if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
3021 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);
3022 exit(1);
3024 if ((x = ast_wait_for_input(fd, 300)) < 0) {
3025 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");
3026 exit(1);
3028 if (!x) {
3029 const char dahdi_timer_error[] = {
3030 "Asterisk has detected a problem with your DAHDI configuration and will shutdown for your protection. You have options:"
3031 "\n\t1. You only have to compile DAHDI support into Asterisk if you need it. One option is to recompile without DAHDI support."
3032 "\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."
3033 "\n\t3. If you need DAHDI services, you must correctly configure DAHDI."
3035 ast_log(LOG_ERROR, "%s\n", dahdi_timer_error);
3036 exit(1);
3038 close(fd);
3042 #endif
3043 threadstorage_init();
3045 astobj2_init();
3047 ast_autoservice_init();
3049 if (load_modules(1)) {
3050 printf(term_quit());
3051 exit(1);
3054 if (dnsmgr_init()) {
3055 printf(term_quit());
3056 exit(1);
3059 ast_http_init();
3061 ast_channels_init();
3063 if (init_manager()) {
3064 printf(term_quit());
3065 exit(1);
3068 if (ast_cdr_engine_init()) {
3069 printf(term_quit());
3070 exit(1);
3073 if (ast_device_state_engine_init()) {
3074 printf(term_quit());
3075 exit(1);
3078 ast_rtp_init();
3080 ast_udptl_init();
3082 if (ast_image_init()) {
3083 printf(term_quit());
3084 exit(1);
3087 if (ast_file_init()) {
3088 printf(term_quit());
3089 exit(1);
3092 if (load_pbx()) {
3093 printf(term_quit());
3094 exit(1);
3097 if (init_framer()) {
3098 printf(term_quit());
3099 exit(1);
3102 if (astdb_init()) {
3103 printf(term_quit());
3104 exit(1);
3107 if (ast_enum_init()) {
3108 printf(term_quit());
3109 exit(1);
3112 if (load_modules(0)) {
3113 printf(term_quit());
3114 exit(1);
3117 dnsmgr_start_refresh();
3119 /* We might have the option of showing a console, but for now just
3120 do nothing... */
3121 if (ast_opt_console && !option_verbose)
3122 ast_verbose(" ]\n");
3123 if (option_verbose || ast_opt_console)
3124 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
3125 if (ast_opt_no_fork)
3126 consolethread = pthread_self();
3128 if (pipe(sig_alert_pipe))
3129 sig_alert_pipe[0] = sig_alert_pipe[1] = -1;
3131 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
3132 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
3134 #ifdef __AST_DEBUG_MALLOC
3135 __ast_mm_init();
3136 #endif
3138 time(&ast_startuptime);
3139 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
3141 if (ast_opt_console) {
3142 /* Console stuff now... */
3143 /* Register our quit function */
3144 char title[256];
3145 pthread_attr_t attr;
3146 pthread_t dont_care;
3148 pthread_attr_init(&attr);
3149 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3150 ast_pthread_create(&dont_care, &attr, monitor_sig_flags, NULL);
3151 pthread_attr_destroy(&attr);
3153 set_icon("Asterisk");
3154 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
3155 set_title(title);
3157 for (;;) {
3158 buf = (char *)el_gets(el, &num);
3160 if (!buf && write(1, "", 1) < 0)
3161 goto lostterm;
3163 if (buf) {
3164 if (buf[strlen(buf)-1] == '\n')
3165 buf[strlen(buf)-1] = '\0';
3167 consolehandler((char *)buf);
3168 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
3169 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
3170 /* Whoa, stdout disappeared from under us... Make /dev/null's */
3171 int fd;
3172 fd = open("/dev/null", O_RDWR);
3173 if (fd > -1) {
3174 dup2(fd, STDOUT_FILENO);
3175 dup2(fd, STDIN_FILENO);
3176 } else
3177 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
3178 break;
3183 monitor_sig_flags(NULL);
3185 lostterm:
3186 return 0;