put this value into the correct property
[asterisk-bristuff.git] / main / asterisk.c
blob929a83b4789fae03972e014eb58c33ac9e51fa28
1 /*
2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, 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 - 2006, Digium, Inc.
34 * Asterisk is a trade mark 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 #include <unistd.h>
65 #include <stdlib.h>
66 #include <sys/time.h>
67 #include <fcntl.h>
68 #include <stdio.h>
69 #include <signal.h>
70 #include <sched.h>
71 #include <sys/socket.h>
72 #include <sys/un.h>
73 #include <sys/wait.h>
74 #include <string.h>
75 #include <errno.h>
76 #include <ctype.h>
77 #include <sys/resource.h>
78 #include <grp.h>
79 #include <pwd.h>
80 #include <sys/stat.h>
81 #ifdef linux
82 #include <sys/prctl.h>
83 #endif
84 #include <regex.h>
86 #ifdef linux
87 #include <sys/prctl.h>
88 #endif
90 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
91 #include <netdb.h>
92 #if defined(SOLARIS)
93 int daemon(int, int); /* defined in libresolv of all places */
94 #endif
95 #endif
97 #include "asterisk/logger.h"
98 #include "asterisk/options.h"
99 #include "asterisk/cli.h"
100 #include "asterisk/channel.h"
101 #include "asterisk/ulaw.h"
102 #include "asterisk/alaw.h"
103 #include "asterisk/callerid.h"
104 #include "asterisk/image.h"
105 #include "asterisk/tdd.h"
106 #include "asterisk/term.h"
107 #include "asterisk/manager.h"
108 #include "asterisk/cdr.h"
109 #include "asterisk/pbx.h"
110 #include "asterisk/enum.h"
111 #include "asterisk/rtp.h"
112 #include "asterisk/http.h"
113 #include "asterisk/udptl.h"
114 #include "asterisk/app.h"
115 #include "asterisk/lock.h"
116 #include "asterisk/utils.h"
117 #include "asterisk/file.h"
118 #include "asterisk/io.h"
119 #include "asterisk/lock.h"
120 #include "editline/histedit.h"
121 #include "asterisk/config.h"
122 #include "asterisk/version.h"
123 #include "asterisk/linkedlists.h"
124 #include "asterisk/devicestate.h"
126 #include "asterisk/doxyref.h" /* Doxygen documentation */
128 #include "../defaults.h"
130 #ifndef AF_LOCAL
131 #define AF_LOCAL AF_UNIX
132 #define PF_LOCAL PF_UNIX
133 #endif
135 #define AST_MAX_CONNECTS 128
136 #define NUM_MSGS 64
138 /*! \brief Welcome message when starting a CLI interface */
139 #define WELCOME_MESSAGE \
140 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
141 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
142 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n"); \
143 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
144 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
145 ast_verbose("certain conditions. Type 'core show license' for details.\n"); \
146 ast_verbose("=========================================================================\n")
148 /*! \defgroup main_options Main Configuration Options
149 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
150 the operating system command line when starting Asterisk
151 Some of them can be changed in the CLI
153 /*! @{ */
155 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
157 int option_verbose; /*!< Verbosity level */
158 int option_debug; /*!< Debug level */
160 double option_maxload; /*!< Max load avg on system */
161 int option_maxcalls; /*!< Max number of active calls */
163 /*! @} */
165 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
166 char debug_filename[AST_FILENAME_MAX] = "";
168 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
169 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
170 pid_t ast_mainpid;
171 struct console {
172 int fd; /*!< File descriptor */
173 int p[2]; /*!< Pipe */
174 pthread_t t; /*!< Thread of handler */
175 int mute; /*!< Is the console muted for logs */
178 struct ast_atexit {
179 void (*func)(void);
180 AST_LIST_ENTRY(ast_atexit) list;
183 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
185 time_t ast_startuptime;
186 time_t ast_lastreloadtime;
188 static History *el_hist;
189 static EditLine *el;
190 static char *remotehostname;
192 struct console consoles[AST_MAX_CONNECTS];
194 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
196 static int ast_el_add_history(char *);
197 static int ast_el_read_history(char *);
198 static int ast_el_write_history(char *);
200 char ast_config_AST_CONFIG_DIR[PATH_MAX];
201 char ast_config_AST_CONFIG_FILE[PATH_MAX];
202 char ast_config_AST_MODULE_DIR[PATH_MAX];
203 char ast_config_AST_SPOOL_DIR[PATH_MAX];
204 char ast_config_AST_MONITOR_DIR[PATH_MAX];
205 char ast_config_AST_VAR_DIR[PATH_MAX];
206 char ast_config_AST_DATA_DIR[PATH_MAX];
207 char ast_config_AST_LOG_DIR[PATH_MAX];
208 char ast_config_AST_AGI_DIR[PATH_MAX];
209 char ast_config_AST_DB[PATH_MAX];
210 char ast_config_AST_KEY_DIR[PATH_MAX];
211 char ast_config_AST_PID[PATH_MAX];
212 char ast_config_AST_SOCKET[PATH_MAX];
213 char ast_config_AST_RUN_DIR[PATH_MAX];
214 char ast_config_AST_RUN_USER[PATH_MAX];
215 char ast_config_AST_RUN_GROUP[PATH_MAX];
216 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
217 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
218 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
219 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
220 char ast_config_AST_SYSTEM_NAME[20] = "";
222 extern const char *ast_build_hostname;
223 extern const char *ast_build_kernel;
224 extern const char *ast_build_machine;
225 extern const char *ast_build_os;
226 extern const char *ast_build_date;
227 extern const char *ast_build_user;
229 static char *_argv[256];
230 static int shuttingdown;
231 static int restartnow;
232 static pthread_t consolethread = AST_PTHREADT_NULL;
234 static char randompool[256];
236 #if !defined(LOW_MEMORY)
237 struct file_version {
238 AST_LIST_ENTRY(file_version) list;
239 const char *file;
240 char *version;
243 static AST_LIST_HEAD_STATIC(file_versions, file_version);
245 void ast_register_file_version(const char *file, const char *version)
247 struct file_version *new;
248 char *work;
249 size_t version_length;
251 work = ast_strdupa(version);
252 work = ast_strip(ast_strip_quoted(work, "$", "$"));
253 version_length = strlen(work) + 1;
255 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
256 return;
258 new->file = file;
259 new->version = (char *) new + sizeof(*new);
260 memcpy(new->version, work, version_length);
261 AST_LIST_LOCK(&file_versions);
262 AST_LIST_INSERT_HEAD(&file_versions, new, list);
263 AST_LIST_UNLOCK(&file_versions);
266 void ast_unregister_file_version(const char *file)
268 struct file_version *find;
270 AST_LIST_LOCK(&file_versions);
271 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
272 if (!strcasecmp(find->file, file)) {
273 AST_LIST_REMOVE_CURRENT(&file_versions, list);
274 break;
277 AST_LIST_TRAVERSE_SAFE_END;
278 AST_LIST_UNLOCK(&file_versions);
279 if (find)
280 free(find);
283 struct thread_list_t {
284 AST_LIST_ENTRY(thread_list_t) list;
285 char *name;
286 pthread_t id;
289 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
291 static char show_threads_help[] =
292 "Usage: core show threads\n"
293 " List threads currently active in the system.\n";
295 void ast_register_thread(char *name)
297 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
299 if (!new)
300 return;
301 new->id = pthread_self();
302 new->name = name; /* steal the allocated memory for the thread name */
303 AST_LIST_LOCK(&thread_list);
304 AST_LIST_INSERT_HEAD(&thread_list, new, list);
305 AST_LIST_UNLOCK(&thread_list);
308 void ast_unregister_thread(void *id)
310 struct thread_list_t *x;
312 AST_LIST_LOCK(&thread_list);
313 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
314 if ((void *) x->id == id) {
315 AST_LIST_REMOVE_CURRENT(&thread_list, list);
316 break;
319 AST_LIST_TRAVERSE_SAFE_END;
320 AST_LIST_UNLOCK(&thread_list);
321 if (x) {
322 free(x->name);
323 free(x);
327 static int handle_show_threads(int fd, int argc, char *argv[])
329 int count = 0;
330 struct thread_list_t *cur;
332 AST_LIST_LOCK(&thread_list);
333 AST_LIST_TRAVERSE(&thread_list, cur, list) {
334 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
335 count++;
337 AST_LIST_UNLOCK(&thread_list);
338 ast_cli(fd, "%d threads listed.\n", count);
339 return 0;
342 struct profile_entry {
343 const char *name;
344 uint64_t scale; /* if non-zero, values are scaled by this */
345 int64_t mark;
346 int64_t value;
347 int64_t events;
350 struct profile_data {
351 int entries;
352 int max_size;
353 struct profile_entry e[0];
356 static struct profile_data *prof_data;
358 /*! \brief allocates a counter with a given name and scale.
359 * \return Returns the identifier of the counter.
361 int ast_add_profile(const char *name, uint64_t scale)
363 int l = sizeof(struct profile_data);
364 int n = 10; /* default entries */
366 if (prof_data == NULL) {
367 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
368 if (prof_data == NULL)
369 return -1;
370 prof_data->entries = 0;
371 prof_data->max_size = n;
373 if (prof_data->entries >= prof_data->max_size) {
374 void *p;
375 n = prof_data->max_size + 20;
376 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
377 if (p == NULL)
378 return -1;
379 prof_data = p;
380 prof_data->max_size = n;
382 n = prof_data->entries++;
383 prof_data->e[n].name = ast_strdup(name);
384 prof_data->e[n].value = 0;
385 prof_data->e[n].events = 0;
386 prof_data->e[n].mark = 0;
387 prof_data->e[n].scale = scale;
388 return n;
391 int64_t ast_profile(int i, int64_t delta)
393 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
394 return 0;
395 if (prof_data->e[i].scale > 1)
396 delta /= prof_data->e[i].scale;
397 prof_data->e[i].value += delta;
398 prof_data->e[i].events++;
399 return prof_data->e[i].value;
402 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
403 #if defined(__FreeBSD__)
404 #include <machine/cpufunc.h>
405 #elif defined(linux)
406 static __inline uint64_t
407 rdtsc(void)
409 uint64_t rv;
411 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
412 return (rv);
414 #endif
415 #else /* supply a dummy function on other platforms */
416 static __inline uint64_t
417 rdtsc(void)
419 return 0;
421 #endif
423 int64_t ast_mark(int i, int startstop)
425 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
426 return 0;
427 if (startstop == 1)
428 prof_data->e[i].mark = rdtsc();
429 else {
430 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
431 if (prof_data->e[i].scale > 1)
432 prof_data->e[i].mark /= prof_data->e[i].scale;
433 prof_data->e[i].value += prof_data->e[i].mark;
434 prof_data->e[i].events++;
436 return prof_data->e[i].mark;
439 static int handle_show_profile_deprecated(int fd, int argc, char *argv[])
441 int i, min, max;
442 char *search = NULL;
444 if (prof_data == NULL)
445 return 0;
447 min = 0;
448 max = prof_data->entries;
449 if (argc >= 3) { /* specific entries */
450 if (isdigit(argv[2][0])) {
451 min = atoi(argv[2]);
452 if (argc == 4 && strcmp(argv[3], "-"))
453 max = atoi(argv[3]);
454 } else
455 search = argv[2];
457 if (max > prof_data->entries)
458 max = prof_data->entries;
459 if (!strcmp(argv[0], "clear")) {
460 for (i= min; i < max; i++) {
461 if (!search || strstr(prof_data->e[i].name, search)) {
462 prof_data->e[i].value = 0;
463 prof_data->e[i].events = 0;
466 return 0;
468 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
469 prof_data->entries, prof_data->max_size);
470 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
471 "Value", "Average", "Name");
472 for (i = min; i < max; i++) {
473 struct profile_entry *e = &prof_data->e[i];
474 if (!search || strstr(prof_data->e[i].name, search))
475 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
477 (long)e->scale,
478 (long)e->events, (long long)e->value,
479 (long long)(e->events ? e->value / e->events : e->value),
480 e->name);
482 return 0;
485 static int handle_show_profile(int fd, int argc, char *argv[])
487 int i, min, max;
488 char *search = NULL;
490 if (prof_data == NULL)
491 return 0;
493 min = 0;
494 max = prof_data->entries;
495 if (argc > 3) { /* specific entries */
496 if (isdigit(argv[3][0])) {
497 min = atoi(argv[3]);
498 if (argc == 5 && strcmp(argv[4], "-"))
499 max = atoi(argv[4]);
500 } else
501 search = argv[3];
503 if (max > prof_data->entries)
504 max = prof_data->entries;
505 if (!strcmp(argv[1], "clear")) {
506 for (i= min; i < max; i++) {
507 if (!search || strstr(prof_data->e[i].name, search)) {
508 prof_data->e[i].value = 0;
509 prof_data->e[i].events = 0;
512 return 0;
514 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
515 prof_data->entries, prof_data->max_size);
516 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
517 "Value", "Average", "Name");
518 for (i = min; i < max; i++) {
519 struct profile_entry *e = &prof_data->e[i];
520 if (!search || strstr(prof_data->e[i].name, search))
521 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
523 (long)e->scale,
524 (long)e->events, (long long)e->value,
525 (long long)(e->events ? e->value / e->events : e->value),
526 e->name);
528 return 0;
531 static char show_version_files_help[] =
532 "Usage: core show file version [like <pattern>]\n"
533 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
534 " Optional regular expression pattern is used to filter the file list.\n";
536 /*! \brief CLI command to list module versions */
537 static int handle_show_version_files(int fd, int argc, char *argv[])
539 #define FORMAT "%-25.25s %-40.40s\n"
540 struct file_version *iterator;
541 regex_t regexbuf;
542 int havepattern = 0;
543 int havename = 0;
544 int count_files = 0;
546 switch (argc) {
547 case 5:
548 if (!strcasecmp(argv[3], "like")) {
549 if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
550 return RESULT_SHOWUSAGE;
551 havepattern = 1;
552 } else
553 return RESULT_SHOWUSAGE;
554 break;
555 case 4:
556 havename = 1;
557 break;
558 case 3:
559 break;
560 default:
561 return RESULT_SHOWUSAGE;
564 ast_cli(fd, FORMAT, "File", "Revision");
565 ast_cli(fd, FORMAT, "----", "--------");
566 AST_LIST_LOCK(&file_versions);
567 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
568 if (havename && strcasecmp(iterator->file, argv[3]))
569 continue;
571 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
572 continue;
574 ast_cli(fd, FORMAT, iterator->file, iterator->version);
575 count_files++;
576 if (havename)
577 break;
579 AST_LIST_UNLOCK(&file_versions);
580 if (!havename) {
581 ast_cli(fd, "%d files listed.\n", count_files);
584 if (havepattern)
585 regfree(&regexbuf);
587 return RESULT_SUCCESS;
588 #undef FORMAT
591 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
593 struct file_version *find;
594 int which = 0;
595 char *ret = NULL;
596 int matchlen = strlen(word);
598 if (pos != 3)
599 return NULL;
601 AST_LIST_LOCK(&file_versions);
602 AST_LIST_TRAVERSE(&file_versions, find, list) {
603 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
604 ret = ast_strdup(find->file);
605 break;
608 AST_LIST_UNLOCK(&file_versions);
610 return ret;
612 #endif /* ! LOW_MEMORY */
614 int ast_register_atexit(void (*func)(void))
616 int res = -1;
617 struct ast_atexit *ae;
618 ast_unregister_atexit(func);
619 AST_LIST_LOCK(&atexits);
620 if ((ae = ast_calloc(1, sizeof(*ae)))) {
621 AST_LIST_INSERT_HEAD(&atexits, ae, list);
622 ae->func = func;
623 res = 0;
625 AST_LIST_UNLOCK(&atexits);
626 return res;
629 void ast_unregister_atexit(void (*func)(void))
631 struct ast_atexit *ae;
632 AST_LIST_LOCK(&atexits);
633 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
634 if (ae->func == func) {
635 AST_LIST_REMOVE_CURRENT(&atexits, list);
636 break;
639 AST_LIST_TRAVERSE_SAFE_END
640 AST_LIST_UNLOCK(&atexits);
643 static int fdprint(int fd, const char *s)
645 return write(fd, s, strlen(s) + 1);
648 /*! \brief NULL handler so we can collect the child exit status */
649 static void null_sig_handler(int signal)
654 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
655 /*! \brief Keep track of how many threads are currently trying to wait*() on
656 * a child process */
657 static unsigned int safe_system_level = 0;
658 static void *safe_system_prev_handler;
660 void ast_replace_sigchld(void)
662 unsigned int level;
664 ast_mutex_lock(&safe_system_lock);
665 level = safe_system_level++;
667 /* only replace the handler if it has not already been done */
668 if (level == 0)
669 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
671 ast_mutex_unlock(&safe_system_lock);
674 void ast_unreplace_sigchld(void)
676 unsigned int level;
678 ast_mutex_lock(&safe_system_lock);
679 level = --safe_system_level;
681 /* only restore the handler if we are the last one */
682 if (level == 0)
683 signal(SIGCHLD, safe_system_prev_handler);
685 ast_mutex_unlock(&safe_system_lock);
688 int ast_safe_system(const char *s)
690 pid_t pid;
691 #ifdef HAVE_WORKING_FORK
692 int x;
693 #endif
694 int res;
695 struct rusage rusage;
696 int status;
698 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
699 ast_replace_sigchld();
701 #ifdef HAVE_WORKING_FORK
702 pid = fork();
703 #else
704 pid = vfork();
705 #endif
707 if (pid == 0) {
708 #ifdef HAVE_WORKING_FORK
709 if (ast_opt_high_priority)
710 ast_set_priority(0);
711 /* Close file descriptors and launch system command */
712 for (x = STDERR_FILENO + 1; x < 4096; x++)
713 close(x);
714 #endif
715 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
716 _exit(1);
717 } else if (pid > 0) {
718 for(;;) {
719 res = wait4(pid, &status, 0, &rusage);
720 if (res > -1) {
721 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
722 break;
723 } else if (errno != EINTR)
724 break;
726 } else {
727 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
728 res = -1;
731 ast_unreplace_sigchld();
732 #else
733 res = -1;
734 #endif
736 return res;
740 * \brief mute or unmute a console from logging
742 void ast_console_toggle_mute(int fd) {
743 int x;
744 for (x = 0;x < AST_MAX_CONNECTS; x++) {
745 if (fd == consoles[x].fd) {
746 if (consoles[x].mute) {
747 consoles[x].mute = 0;
748 ast_cli(fd, "Console is not muted anymore.\n");
749 } else {
750 consoles[x].mute = 1;
751 ast_cli(fd, "Console is muted.\n");
753 return;
756 ast_cli(fd, "Couldn't find remote console.\n");
760 * \brief log the string to all attached console clients
762 static void ast_network_puts_mutable(const char *string)
764 int x;
765 for (x = 0;x < AST_MAX_CONNECTS; x++) {
766 if (consoles[x].mute)
767 continue;
768 if (consoles[x].fd > -1)
769 fdprint(consoles[x].p[1], string);
774 * \brief log the string to the console, and all attached
775 * console clients
777 void ast_console_puts_mutable(const char *string)
779 fputs(string, stdout);
780 fflush(stdout);
781 ast_network_puts_mutable(string);
785 * \brief write the string to all attached console clients
787 static void ast_network_puts(const char *string)
789 int x;
790 for (x=0; x < AST_MAX_CONNECTS; x++) {
791 if (consoles[x].fd > -1)
792 fdprint(consoles[x].p[1], string);
797 * write the string to the console, and all attached
798 * console clients
800 void ast_console_puts(const char *string)
802 fputs(string, stdout);
803 fflush(stdout);
804 ast_network_puts(string);
807 static void network_verboser(const char *s)
809 ast_network_puts_mutable(s);
812 static pthread_t lthread;
814 static void *netconsole(void *vconsole)
816 struct console *con = vconsole;
817 char hostname[MAXHOSTNAMELEN] = "";
818 char tmp[512];
819 int res;
820 struct pollfd fds[2];
822 if (gethostname(hostname, sizeof(hostname)-1))
823 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
824 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
825 fdprint(con->fd, tmp);
826 for(;;) {
827 fds[0].fd = con->fd;
828 fds[0].events = POLLIN;
829 fds[0].revents = 0;
830 fds[1].fd = con->p[0];
831 fds[1].events = POLLIN;
832 fds[1].revents = 0;
834 res = poll(fds, 2, -1);
835 if (res < 0) {
836 if (errno != EINTR)
837 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
838 continue;
840 if (fds[0].revents) {
841 res = read(con->fd, tmp, sizeof(tmp));
842 if (res < 1) {
843 break;
845 tmp[res] = 0;
846 ast_cli_command(con->fd, tmp);
848 if (fds[1].revents) {
849 res = read(con->p[0], tmp, sizeof(tmp));
850 if (res < 1) {
851 ast_log(LOG_ERROR, "read returned %d\n", res);
852 break;
854 res = write(con->fd, tmp, res);
855 if (res < 1)
856 break;
859 if (option_verbose > 2)
860 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
861 close(con->fd);
862 close(con->p[0]);
863 close(con->p[1]);
864 con->fd = -1;
866 return NULL;
869 static void *listener(void *unused)
871 struct sockaddr_un sunaddr;
872 int s;
873 socklen_t len;
874 int x;
875 int flags;
876 struct pollfd fds[1];
877 pthread_attr_t attr;
878 pthread_attr_init(&attr);
879 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
880 for (;;) {
881 if (ast_socket < 0)
882 return NULL;
883 fds[0].fd = ast_socket;
884 fds[0].events = POLLIN;
885 s = poll(fds, 1, -1);
886 pthread_testcancel();
887 if (s < 0) {
888 if (errno != EINTR)
889 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
890 continue;
892 len = sizeof(sunaddr);
893 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
894 if (s < 0) {
895 if (errno != EINTR)
896 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
897 } else {
898 for (x = 0; x < AST_MAX_CONNECTS; x++) {
899 if (consoles[x].fd < 0) {
900 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
901 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
902 consoles[x].fd = -1;
903 fdprint(s, "Server failed to create pipe\n");
904 close(s);
905 break;
907 flags = fcntl(consoles[x].p[1], F_GETFL);
908 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
909 consoles[x].fd = s;
910 consoles[x].mute = ast_opt_mute;
911 if (ast_pthread_create_background(&consoles[x].t, &attr, netconsole, &consoles[x])) {
912 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
913 close(consoles[x].p[0]);
914 close(consoles[x].p[1]);
915 consoles[x].fd = -1;
916 fdprint(s, "Server failed to spawn thread\n");
917 close(s);
919 break;
922 if (x >= AST_MAX_CONNECTS) {
923 fdprint(s, "No more connections allowed\n");
924 ast_log(LOG_WARNING, "No more connections allowed\n");
925 close(s);
926 } else if (consoles[x].fd > -1) {
927 if (option_verbose > 2)
928 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
932 return NULL;
935 static int ast_makesocket(void)
937 struct sockaddr_un sunaddr;
938 int res;
939 int x;
940 uid_t uid = -1;
941 gid_t gid = -1;
943 for (x = 0; x < AST_MAX_CONNECTS; x++)
944 consoles[x].fd = -1;
945 unlink(ast_config_AST_SOCKET);
946 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
947 if (ast_socket < 0) {
948 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
949 return -1;
951 memset(&sunaddr, 0, sizeof(sunaddr));
952 sunaddr.sun_family = AF_LOCAL;
953 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
954 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
955 if (res) {
956 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
957 close(ast_socket);
958 ast_socket = -1;
959 return -1;
961 res = listen(ast_socket, 2);
962 if (res < 0) {
963 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
964 close(ast_socket);
965 ast_socket = -1;
966 return -1;
968 ast_register_verbose(network_verboser);
969 ast_pthread_create_background(&lthread, NULL, listener, NULL);
971 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
972 struct passwd *pw;
973 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
974 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
975 } else {
976 uid = pw->pw_uid;
980 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
981 struct group *grp;
982 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
983 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
984 } else {
985 gid = grp->gr_gid;
989 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
990 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
992 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
993 int p1;
994 mode_t p;
995 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
996 p = p1;
997 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
998 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1001 return 0;
1004 static int ast_tryconnect(void)
1006 struct sockaddr_un sunaddr;
1007 int res;
1008 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1009 if (ast_consock < 0) {
1010 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1011 return 0;
1013 memset(&sunaddr, 0, sizeof(sunaddr));
1014 sunaddr.sun_family = AF_LOCAL;
1015 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1016 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1017 if (res) {
1018 close(ast_consock);
1019 ast_consock = -1;
1020 return 0;
1021 } else
1022 return 1;
1025 /*! \brief Urgent handler
1027 Called by soft_hangup to interrupt the poll, read, or other
1028 system call. We don't actually need to do anything though.
1029 Remember: Cannot EVER ast_log from within a signal handler
1031 static void urg_handler(int num)
1033 signal(num, urg_handler);
1034 return;
1037 static void hup_handler(int num)
1039 if (option_verbose > 1)
1040 printf("Received HUP signal -- Reloading configs\n");
1041 if (restartnow)
1042 execvp(_argv[0], _argv);
1043 /* XXX This could deadlock XXX */
1044 ast_module_reload(NULL);
1045 signal(num, hup_handler);
1048 static void child_handler(int sig)
1050 /* Must not ever ast_log or ast_verbose within signal handler */
1051 int n, status;
1054 * Reap all dead children -- not just one
1056 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1058 if (n == 0 && option_debug)
1059 printf("Huh? Child handler, but nobody there?\n");
1060 signal(sig, child_handler);
1063 /*! \brief Set an X-term or screen title */
1064 static void set_title(char *text)
1066 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1067 fprintf(stdout, "\033]2;%s\007", text);
1070 static void set_icon(char *text)
1072 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1073 fprintf(stdout, "\033]1;%s\007", text);
1076 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1077 else. If your PBX has heavy activity on it, this is a good thing. */
1078 int ast_set_priority(int pri)
1080 struct sched_param sched;
1081 memset(&sched, 0, sizeof(sched));
1082 #ifdef __linux__
1083 if (pri) {
1084 sched.sched_priority = 10;
1085 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1086 ast_log(LOG_WARNING, "Unable to set high priority\n");
1087 return -1;
1088 } else
1089 if (option_verbose)
1090 ast_verbose("Set to realtime thread\n");
1091 } else {
1092 sched.sched_priority = 0;
1093 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
1094 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1095 return -1;
1098 #else
1099 if (pri) {
1100 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1101 ast_log(LOG_WARNING, "Unable to set high priority\n");
1102 return -1;
1103 } else
1104 if (option_verbose)
1105 ast_verbose("Set to high priority\n");
1106 } else {
1107 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1108 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1109 return -1;
1112 #endif
1113 return 0;
1116 static void ast_run_atexits(void)
1118 struct ast_atexit *ae;
1119 AST_LIST_LOCK(&atexits);
1120 AST_LIST_TRAVERSE(&atexits, ae, list) {
1121 if (ae->func)
1122 ae->func();
1124 AST_LIST_UNLOCK(&atexits);
1127 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1129 char filename[80] = "";
1130 time_t s,e;
1131 int x;
1132 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1133 ast_cdr_engine_term();
1134 if (safeshutdown) {
1135 shuttingdown = 1;
1136 if (!nice) {
1137 /* Begin shutdown routine, hanging up active channels */
1138 ast_begin_shutdown(1);
1139 if (option_verbose && ast_opt_console)
1140 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1141 time(&s);
1142 for (;;) {
1143 time(&e);
1144 /* Wait up to 15 seconds for all channels to go away */
1145 if ((e - s) > 15)
1146 break;
1147 if (!ast_active_channels())
1148 break;
1149 if (!shuttingdown)
1150 break;
1151 /* Sleep 1/10 of a second */
1152 usleep(100000);
1154 } else {
1155 if (nice < 2)
1156 ast_begin_shutdown(0);
1157 if (option_verbose && ast_opt_console)
1158 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1159 for (;;) {
1160 if (!ast_active_channels())
1161 break;
1162 if (!shuttingdown)
1163 break;
1164 sleep(1);
1168 if (!shuttingdown) {
1169 if (option_verbose && ast_opt_console)
1170 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1171 return;
1174 if (ast_opt_console || ast_opt_remote) {
1175 if (getenv("HOME"))
1176 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1177 if (!ast_strlen_zero(filename))
1178 ast_el_write_history(filename);
1179 if (el != NULL)
1180 el_end(el);
1181 if (el_hist != NULL)
1182 history_end(el_hist);
1184 if (option_verbose)
1185 ast_verbose("Executing last minute cleanups\n");
1186 ast_run_atexits();
1187 /* Called on exit */
1188 if (option_verbose && ast_opt_console)
1189 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1190 if (option_debug)
1191 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1192 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1193 if (ast_socket > -1) {
1194 pthread_cancel(lthread);
1195 close(ast_socket);
1196 ast_socket = -1;
1197 unlink(ast_config_AST_SOCKET);
1199 if (ast_consock > -1)
1200 close(ast_consock);
1201 if (!ast_opt_remote)
1202 unlink(ast_config_AST_PID);
1203 printf(term_quit());
1204 if (restart) {
1205 if (option_verbose || ast_opt_console)
1206 ast_verbose("Preparing for Asterisk restart...\n");
1207 /* Mark all FD's for closing on exec */
1208 for (x=3; x < 32768; x++) {
1209 fcntl(x, F_SETFD, FD_CLOEXEC);
1211 if (option_verbose || ast_opt_console)
1212 ast_verbose("Restarting Asterisk NOW...\n");
1213 restartnow = 1;
1215 /* close logger */
1216 close_logger();
1218 /* If there is a consolethread running send it a SIGHUP
1219 so it can execvp, otherwise we can do it ourselves */
1220 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1221 pthread_kill(consolethread, SIGHUP);
1222 /* Give the signal handler some time to complete */
1223 sleep(2);
1224 } else
1225 execvp(_argv[0], _argv);
1227 } else {
1228 /* close logger */
1229 close_logger();
1231 exit(0);
1234 static void __quit_handler(int num)
1236 quit_handler(num, 0, 1, 0);
1239 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1241 const char *c;
1242 if (!strncmp(s, cmp, strlen(cmp))) {
1243 c = s + strlen(cmp);
1244 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1245 return c;
1247 return NULL;
1250 static void console_verboser(const char *s)
1252 char tmp[80];
1253 const char *c = NULL;
1255 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1256 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1257 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1258 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1259 fputs(tmp, stdout);
1260 fputs(c, stdout);
1261 } else
1262 fputs(s, stdout);
1264 fflush(stdout);
1266 /* Wake up a poll()ing console */
1267 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1268 pthread_kill(consolethread, SIGURG);
1271 static int ast_all_zeros(char *s)
1273 while (*s) {
1274 if (*s > 32)
1275 return 0;
1276 s++;
1278 return 1;
1281 static void consolehandler(char *s)
1283 printf(term_end());
1284 fflush(stdout);
1286 /* Called when readline data is available */
1287 if (!ast_all_zeros(s))
1288 ast_el_add_history(s);
1289 /* The real handler for bang */
1290 if (s[0] == '!') {
1291 if (s[1])
1292 ast_safe_system(s+1);
1293 else
1294 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1295 } else
1296 ast_cli_command(STDOUT_FILENO, s);
1299 static int remoteconsolehandler(char *s)
1301 int ret = 0;
1303 /* Called when readline data is available */
1304 if (!ast_all_zeros(s))
1305 ast_el_add_history(s);
1306 /* The real handler for bang */
1307 if (s[0] == '!') {
1308 if (s[1])
1309 ast_safe_system(s+1);
1310 else
1311 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1312 ret = 1;
1314 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1315 (s[4] == '\0' || isspace(s[4]))) {
1316 quit_handler(0, 0, 0, 0);
1317 ret = 1;
1320 return ret;
1323 static char abort_halt_help[] =
1324 "Usage: abort shutdown\n"
1325 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1326 " call operations.\n";
1328 static char shutdown_now_help[] =
1329 "Usage: stop now\n"
1330 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1332 static char shutdown_gracefully_help[] =
1333 "Usage: stop gracefully\n"
1334 " Causes Asterisk to not accept new calls, and exit when all\n"
1335 " active calls have terminated normally.\n";
1337 static char shutdown_when_convenient_help[] =
1338 "Usage: stop when convenient\n"
1339 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1341 static char restart_now_help[] =
1342 "Usage: restart now\n"
1343 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1344 " restart.\n";
1346 static char restart_gracefully_help[] =
1347 "Usage: restart gracefully\n"
1348 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1349 " restart when all active calls have ended.\n";
1351 static char restart_when_convenient_help[] =
1352 "Usage: restart when convenient\n"
1353 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1355 static char bang_help[] =
1356 "Usage: !<command>\n"
1357 " Executes a given shell command\n";
1359 static char show_warranty_help[] =
1360 "Usage: core show warranty\n"
1361 " Shows the warranty (if any) for this copy of Asterisk.\n";
1363 static char show_license_help[] =
1364 "Usage: core show license\n"
1365 " Shows the license(s) for this copy of Asterisk.\n";
1367 static char version_help[] =
1368 "Usage: core show version\n"
1369 " Shows Asterisk version information.\n";
1371 static int handle_version(int fd, int argc, char *argv[])
1373 if (argc != 3)
1374 return RESULT_SHOWUSAGE;
1375 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1376 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1377 ast_build_machine, ast_build_os, ast_build_date);
1378 return RESULT_SUCCESS;
1381 #if 0
1382 static int handle_quit(int fd, int argc, char *argv[])
1384 if (argc != 1)
1385 return RESULT_SHOWUSAGE;
1386 quit_handler(0, 0, 1, 0);
1387 return RESULT_SUCCESS;
1389 #endif
1391 static int handle_shutdown_now(int fd, int argc, char *argv[])
1393 if (argc != 2)
1394 return RESULT_SHOWUSAGE;
1395 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1396 return RESULT_SUCCESS;
1399 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1401 if (argc != 2)
1402 return RESULT_SHOWUSAGE;
1403 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1404 return RESULT_SUCCESS;
1407 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1409 if (argc != 3)
1410 return RESULT_SHOWUSAGE;
1411 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1412 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1413 return RESULT_SUCCESS;
1416 static int handle_restart_now(int fd, int argc, char *argv[])
1418 if (argc != 2)
1419 return RESULT_SHOWUSAGE;
1420 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1421 return RESULT_SUCCESS;
1424 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1426 if (argc != 2)
1427 return RESULT_SHOWUSAGE;
1428 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1429 return RESULT_SUCCESS;
1432 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1434 if (argc != 3)
1435 return RESULT_SHOWUSAGE;
1436 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1437 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1438 return RESULT_SUCCESS;
1441 static int handle_abort_halt(int fd, int argc, char *argv[])
1443 if (argc != 2)
1444 return RESULT_SHOWUSAGE;
1445 ast_cancel_shutdown();
1446 shuttingdown = 0;
1447 return RESULT_SUCCESS;
1450 static int handle_bang(int fd, int argc, char *argv[])
1452 return RESULT_SUCCESS;
1454 static const char *warranty_lines[] = {
1455 "\n",
1456 " NO WARRANTY\n",
1457 "\n",
1458 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1459 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1460 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1461 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1462 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1463 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1464 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1465 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1466 "REPAIR OR CORRECTION.\n",
1467 "\n",
1468 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1469 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1470 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1471 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1472 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1473 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1474 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1475 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1476 "POSSIBILITY OF SUCH DAMAGES.\n",
1479 static int show_warranty(int fd, int argc, char *argv[])
1481 int x;
1483 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1484 ast_cli(fd, (char *) warranty_lines[x]);
1486 return RESULT_SUCCESS;
1489 static const char *license_lines[] = {
1490 "\n",
1491 "This program is free software; you can redistribute it and/or modify\n",
1492 "it under the terms of the GNU General Public License version 2 as\n",
1493 "published by the Free Software Foundation.\n",
1494 "\n",
1495 "This program also contains components licensed under other licenses.\n",
1496 "They include:\n",
1497 "\n",
1498 "This program is distributed in the hope that it will be useful,\n",
1499 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1500 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1501 "GNU General Public License for more details.\n",
1502 "\n",
1503 "You should have received a copy of the GNU General Public License\n",
1504 "along with this program; if not, write to the Free Software\n",
1505 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1508 static int show_license(int fd, int argc, char *argv[])
1510 int x;
1512 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1513 ast_cli(fd, (char *) license_lines[x]);
1515 return RESULT_SUCCESS;
1518 #define ASTERISK_PROMPT "*CLI> "
1520 #define ASTERISK_PROMPT2 "%s*CLI> "
1522 #if !defined(LOW_MEMORY)
1523 static struct ast_cli_entry cli_show_version_files_deprecated = {
1524 { "show", "version", "files", NULL },
1525 handle_show_version_files, NULL,
1526 NULL, complete_show_version_files };
1528 static struct ast_cli_entry cli_show_profile_deprecated = {
1529 { "show", "profile", NULL },
1530 handle_show_profile_deprecated, NULL,
1531 NULL };
1533 static struct ast_cli_entry cli_clear_profile_deprecated = {
1534 { "clear", "profile", NULL },
1535 handle_show_profile_deprecated, NULL,
1536 NULL };
1537 #endif /* ! LOW_MEMORY */
1539 static struct ast_cli_entry cli_asterisk[] = {
1540 { { "abort", "halt", NULL },
1541 handle_abort_halt, "Cancel a running halt",
1542 abort_halt_help },
1544 { { "stop", "now", NULL },
1545 handle_shutdown_now, "Shut down Asterisk immediately",
1546 shutdown_now_help },
1548 { { "stop", "gracefully", NULL },
1549 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1550 shutdown_gracefully_help },
1552 { { "stop", "when", "convenient", NULL },
1553 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1554 shutdown_when_convenient_help },
1556 { { "restart", "now", NULL },
1557 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1559 { { "restart", "gracefully", NULL },
1560 handle_restart_gracefully, "Restart Asterisk gracefully",
1561 restart_gracefully_help },
1563 { { "restart", "when", "convenient", NULL },
1564 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1565 restart_when_convenient_help },
1567 { { "core", "show", "warranty", NULL },
1568 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1569 show_warranty_help },
1571 { { "core", "show", "license", NULL },
1572 show_license, "Show the license(s) for this copy of Asterisk",
1573 show_license_help },
1575 { { "core", "show", "version", NULL },
1576 handle_version, "Display version info",
1577 version_help },
1579 { { "!", NULL },
1580 handle_bang, "Execute a shell command",
1581 bang_help },
1583 #if !defined(LOW_MEMORY)
1584 { { "core", "show", "file", "version", NULL },
1585 handle_show_version_files, "List versions of files used to build Asterisk",
1586 show_version_files_help, complete_show_version_files, &cli_show_version_files_deprecated },
1588 { { "core", "show", "threads", NULL },
1589 handle_show_threads, "Show running threads",
1590 show_threads_help },
1592 { { "core", "show", "profile", NULL },
1593 handle_show_profile, "Display profiling info",
1594 NULL, NULL, &cli_show_profile_deprecated },
1596 { { "core", "clear", "profile", NULL },
1597 handle_show_profile, "Clear profiling info",
1598 NULL, NULL, &cli_clear_profile_deprecated },
1599 #endif /* ! LOW_MEMORY */
1602 static int ast_el_read_char(EditLine *el, char *cp)
1604 int num_read = 0;
1605 int lastpos = 0;
1606 struct pollfd fds[2];
1607 int res;
1608 int max;
1609 char buf[512];
1611 for (;;) {
1612 max = 1;
1613 fds[0].fd = ast_consock;
1614 fds[0].events = POLLIN;
1615 if (!ast_opt_exec) {
1616 fds[1].fd = STDIN_FILENO;
1617 fds[1].events = POLLIN;
1618 max++;
1620 res = poll(fds, max, -1);
1621 if (res < 0) {
1622 if (errno == EINTR)
1623 continue;
1624 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1625 break;
1628 if (!ast_opt_exec && fds[1].revents) {
1629 num_read = read(STDIN_FILENO, cp, 1);
1630 if (num_read < 1) {
1631 break;
1632 } else
1633 return (num_read);
1635 if (fds[0].revents) {
1636 res = read(ast_consock, buf, sizeof(buf) - 1);
1637 /* if the remote side disappears exit */
1638 if (res < 1) {
1639 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1640 if (!ast_opt_reconnect) {
1641 quit_handler(0, 0, 0, 0);
1642 } else {
1643 int tries;
1644 int reconnects_per_second = 20;
1645 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1646 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1647 if (ast_tryconnect()) {
1648 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1649 printf(term_quit());
1650 WELCOME_MESSAGE;
1651 break;
1652 } else {
1653 usleep(1000000 / reconnects_per_second);
1656 if (tries >= 30 * reconnects_per_second) {
1657 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1658 quit_handler(0, 0, 0, 0);
1663 buf[res] = '\0';
1665 if (!ast_opt_exec && !lastpos)
1666 write(STDOUT_FILENO, "\r", 1);
1667 write(STDOUT_FILENO, buf, res);
1668 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1669 *cp = CC_REFRESH;
1670 return(1);
1671 } else {
1672 lastpos = 1;
1677 *cp = '\0';
1678 return (0);
1681 static char *cli_prompt(EditLine *el)
1683 static char prompt[200];
1684 char *pfmt;
1685 int color_used = 0;
1686 char term_code[20];
1688 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1689 char *t = pfmt, *p = prompt;
1690 memset(prompt, 0, sizeof(prompt));
1691 while (*t != '\0' && *p < sizeof(prompt)) {
1692 if (*t == '%') {
1693 char hostname[MAXHOSTNAMELEN]="";
1694 int i;
1695 time_t ts;
1696 struct tm tm;
1697 #ifdef linux
1698 FILE *LOADAVG;
1699 #endif
1700 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1702 t++;
1703 switch (*t) {
1704 case 'C': /* color */
1705 t++;
1706 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1707 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1708 t += i - 1;
1709 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1710 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1711 t += i - 1;
1714 /* If the color has been reset correctly, then there's no need to reset it later */
1715 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1716 color_used = 0;
1717 } else {
1718 color_used = 1;
1720 break;
1721 case 'd': /* date */
1722 memset(&tm, 0, sizeof(tm));
1723 time(&ts);
1724 if (localtime_r(&ts, &tm)) {
1725 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1727 break;
1728 case 'h': /* hostname */
1729 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1730 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1731 } else {
1732 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1734 break;
1735 case 'H': /* short hostname */
1736 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1737 for (i = 0; i < sizeof(hostname); i++) {
1738 if (hostname[i] == '.') {
1739 hostname[i] = '\0';
1740 break;
1743 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1744 } else {
1745 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1747 break;
1748 #ifdef linux
1749 case 'l': /* load avg */
1750 t++;
1751 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1752 float avg1, avg2, avg3;
1753 int actproc, totproc, npid, which;
1754 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1755 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1756 if (sscanf(t, "%d", &which) == 1) {
1757 switch (which) {
1758 case 1:
1759 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1760 break;
1761 case 2:
1762 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1763 break;
1764 case 3:
1765 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1766 break;
1767 case 4:
1768 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1769 break;
1770 case 5:
1771 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1772 break;
1776 break;
1777 #endif
1778 case 's': /* Asterisk system name (from asterisk.conf) */
1779 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1780 break;
1781 case 't': /* time */
1782 memset(&tm, 0, sizeof(tm));
1783 time(&ts);
1784 if (localtime_r(&ts, &tm)) {
1785 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1787 break;
1788 case '#': /* process console or remote? */
1789 if (!ast_opt_remote) {
1790 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1791 } else {
1792 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1794 break;
1795 case '%': /* literal % */
1796 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1797 break;
1798 case '\0': /* % is last character - prevent bug */
1799 t--;
1800 break;
1802 while (*p != '\0') {
1803 p++;
1805 t++;
1806 } else {
1807 *p = *t;
1808 p++;
1809 t++;
1812 if (color_used) {
1813 /* Force colors back to normal at end */
1814 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1815 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1816 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1817 } else {
1818 strncat(p, term_code, sizeof(term_code));
1821 } else if (remotehostname)
1822 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1823 else
1824 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1826 return(prompt);
1829 static char **ast_el_strtoarr(char *buf)
1831 char **match_list = NULL, *retstr;
1832 size_t match_list_len;
1833 int matches = 0;
1835 match_list_len = 1;
1836 while ( (retstr = strsep(&buf, " ")) != NULL) {
1838 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1839 break;
1840 if (matches + 1 >= match_list_len) {
1841 match_list_len <<= 1;
1842 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1843 /* TODO: Handle memory allocation failure */
1847 match_list[matches++] = strdup(retstr);
1850 if (!match_list)
1851 return (char **) NULL;
1853 if (matches >= match_list_len) {
1854 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1855 /* TODO: Handle memory allocation failure */
1859 match_list[matches] = (char *) NULL;
1861 return match_list;
1864 static int ast_el_sort_compare(const void *i1, const void *i2)
1866 char *s1, *s2;
1868 s1 = ((char **)i1)[0];
1869 s2 = ((char **)i2)[0];
1871 return strcasecmp(s1, s2);
1874 static int ast_cli_display_match_list(char **matches, int len, int max)
1876 int i, idx, limit, count;
1877 int screenwidth = 0;
1878 int numoutput = 0, numoutputline = 0;
1880 screenwidth = ast_get_termcols(STDOUT_FILENO);
1882 /* find out how many entries can be put on one line, with two spaces between strings */
1883 limit = screenwidth / (max + 2);
1884 if (limit == 0)
1885 limit = 1;
1887 /* how many lines of output */
1888 count = len / limit;
1889 if (count * limit < len)
1890 count++;
1892 idx = 1;
1894 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1896 for (; count > 0; count--) {
1897 numoutputline = 0;
1898 for (i=0; i < limit && matches[idx]; i++, idx++) {
1900 /* Don't print dupes */
1901 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1902 i--;
1903 free(matches[idx]);
1904 matches[idx] = NULL;
1905 continue;
1908 numoutput++;
1909 numoutputline++;
1910 fprintf(stdout, "%-*s ", max, matches[idx]);
1911 free(matches[idx]);
1912 matches[idx] = NULL;
1914 if (numoutputline > 0)
1915 fprintf(stdout, "\n");
1918 return numoutput;
1922 static char *cli_complete(EditLine *el, int ch)
1924 int len = 0;
1925 char *ptr;
1926 int nummatches = 0;
1927 char **matches;
1928 int retval = CC_ERROR;
1929 char buf[2048];
1930 int res;
1932 LineInfo *lf = (LineInfo *)el_line(el);
1934 *(char *)lf->cursor = '\0';
1935 ptr = (char *)lf->cursor;
1936 if (ptr) {
1937 while (ptr > lf->buffer) {
1938 if (isspace(*ptr)) {
1939 ptr++;
1940 break;
1942 ptr--;
1946 len = lf->cursor - ptr;
1948 if (ast_opt_remote) {
1949 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1950 fdprint(ast_consock, buf);
1951 res = read(ast_consock, buf, sizeof(buf));
1952 buf[res] = '\0';
1953 nummatches = atoi(buf);
1955 if (nummatches > 0) {
1956 char *mbuf;
1957 int mlen = 0, maxmbuf = 2048;
1958 /* Start with a 2048 byte buffer */
1959 if (!(mbuf = ast_malloc(maxmbuf)))
1960 return (char *)(CC_ERROR);
1961 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1962 fdprint(ast_consock, buf);
1963 res = 0;
1964 mbuf[0] = '\0';
1965 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1966 if (mlen + 1024 > maxmbuf) {
1967 /* Every step increment buffer 1024 bytes */
1968 maxmbuf += 1024;
1969 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1970 return (char *)(CC_ERROR);
1972 /* Only read 1024 bytes at a time */
1973 res = read(ast_consock, mbuf + mlen, 1024);
1974 if (res > 0)
1975 mlen += res;
1977 mbuf[mlen] = '\0';
1979 matches = ast_el_strtoarr(mbuf);
1980 free(mbuf);
1981 } else
1982 matches = (char **) NULL;
1983 } else {
1984 char **p, *oldbuf=NULL;
1985 nummatches = 0;
1986 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1987 for (p = matches; p && *p; p++) {
1988 if (!oldbuf || strcmp(*p,oldbuf))
1989 nummatches++;
1990 oldbuf = *p;
1994 if (matches) {
1995 int i;
1996 int matches_num, maxlen, match_len;
1998 if (matches[0][0] != '\0') {
1999 el_deletestr(el, (int) len);
2000 el_insertstr(el, matches[0]);
2001 retval = CC_REFRESH;
2004 if (nummatches == 1) {
2005 /* Found an exact match */
2006 el_insertstr(el, " ");
2007 retval = CC_REFRESH;
2008 } else {
2009 /* Must be more than one match */
2010 for (i=1, maxlen=0; matches[i]; i++) {
2011 match_len = strlen(matches[i]);
2012 if (match_len > maxlen)
2013 maxlen = match_len;
2015 matches_num = i - 1;
2016 if (matches_num >1) {
2017 fprintf(stdout, "\n");
2018 ast_cli_display_match_list(matches, nummatches, maxlen);
2019 retval = CC_REDISPLAY;
2020 } else {
2021 el_insertstr(el," ");
2022 retval = CC_REFRESH;
2025 free(matches);
2028 return (char *)(long)retval;
2031 static int ast_el_initialize(void)
2033 HistEvent ev;
2034 char *editor = getenv("AST_EDITOR");
2036 if (el != NULL)
2037 el_end(el);
2038 if (el_hist != NULL)
2039 history_end(el_hist);
2041 el = el_init("asterisk", stdin, stdout, stderr);
2042 el_set(el, EL_PROMPT, cli_prompt);
2044 el_set(el, EL_EDITMODE, 1);
2045 el_set(el, EL_EDITOR, editor ? editor : "emacs");
2046 el_hist = history_init();
2047 if (!el || !el_hist)
2048 return -1;
2050 /* setup history with 100 entries */
2051 history(el_hist, &ev, H_SETSIZE, 100);
2053 el_set(el, EL_HIST, history, el_hist);
2055 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2056 /* Bind <tab> to command completion */
2057 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2058 /* Bind ? to command completion */
2059 el_set(el, EL_BIND, "?", "ed-complete", NULL);
2060 /* Bind ^D to redisplay */
2061 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2063 return 0;
2066 static int ast_el_add_history(char *buf)
2068 HistEvent ev;
2070 if (el_hist == NULL || el == NULL)
2071 ast_el_initialize();
2072 if (strlen(buf) > 256)
2073 return 0;
2074 return (history(el_hist, &ev, H_ENTER, buf));
2077 static int ast_el_write_history(char *filename)
2079 HistEvent ev;
2081 if (el_hist == NULL || el == NULL)
2082 ast_el_initialize();
2084 return (history(el_hist, &ev, H_SAVE, filename));
2087 static int ast_el_read_history(char *filename)
2089 char buf[256];
2090 FILE *f;
2091 int ret = -1;
2093 if (el_hist == NULL || el == NULL)
2094 ast_el_initialize();
2096 if ((f = fopen(filename, "r")) == NULL)
2097 return ret;
2099 while (!feof(f)) {
2100 fgets(buf, sizeof(buf), f);
2101 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2102 continue;
2103 if (ast_all_zeros(buf))
2104 continue;
2105 if ((ret = ast_el_add_history(buf)) == -1)
2106 break;
2108 fclose(f);
2110 return ret;
2113 static void ast_remotecontrol(char * data)
2115 char buf[80];
2116 int res;
2117 char filename[80] = "";
2118 char *hostname;
2119 char *cpid;
2120 char *version;
2121 int pid;
2122 char tmp[80];
2123 char *stringp = NULL;
2125 char *ebuf;
2126 int num = 0;
2128 read(ast_consock, buf, sizeof(buf));
2129 if (data)
2130 write(ast_consock, data, strlen(data) + 1);
2131 stringp = buf;
2132 hostname = strsep(&stringp, "/");
2133 cpid = strsep(&stringp, "/");
2134 version = strsep(&stringp, "\n");
2135 if (!version)
2136 version = "<Version Unknown>";
2137 stringp = hostname;
2138 strsep(&stringp, ".");
2139 if (cpid)
2140 pid = atoi(cpid);
2141 else
2142 pid = -1;
2143 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2144 fdprint(ast_consock, tmp);
2145 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2146 fdprint(ast_consock, tmp);
2147 if (ast_opt_mute) {
2148 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2149 fdprint(ast_consock, tmp);
2151 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2152 remotehostname = hostname;
2153 if (getenv("HOME"))
2154 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2155 if (el_hist == NULL || el == NULL)
2156 ast_el_initialize();
2158 el_set(el, EL_GETCFN, ast_el_read_char);
2160 if (!ast_strlen_zero(filename))
2161 ast_el_read_history(filename);
2163 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2164 char tempchar;
2165 struct pollfd fds;
2166 fds.fd = ast_consock;
2167 fds.events = POLLIN;
2168 fds.revents = 0;
2169 while (poll(&fds, 1, 100) > 0)
2170 ast_el_read_char(el, &tempchar);
2171 return;
2173 for (;;) {
2174 ebuf = (char *)el_gets(el, &num);
2176 if (!ast_strlen_zero(ebuf)) {
2177 if (ebuf[strlen(ebuf)-1] == '\n')
2178 ebuf[strlen(ebuf)-1] = '\0';
2179 if (!remoteconsolehandler(ebuf)) {
2180 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2181 if (res < 1) {
2182 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2183 break;
2188 printf("\nDisconnected from Asterisk server\n");
2191 static int show_version(void)
2193 printf("Asterisk " ASTERISK_VERSION "\n");
2194 return 0;
2197 static int show_cli_help(void) {
2198 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2199 printf("Usage: asterisk [OPTIONS]\n");
2200 printf("Valid Options:\n");
2201 printf(" -V Display version number and exit\n");
2202 printf(" -C <configfile> Use an alternate configuration file\n");
2203 printf(" -G <group> Run as a group other than the caller\n");
2204 printf(" -U <user> Run as a user other than the caller\n");
2205 printf(" -c Provide console CLI\n");
2206 printf(" -d Enable extra debugging\n");
2207 #if HAVE_WORKING_FORK
2208 printf(" -f Do not fork\n");
2209 printf(" -F Always fork\n");
2210 #endif
2211 printf(" -g Dump core in case of a crash\n");
2212 printf(" -h This help screen\n");
2213 printf(" -i Initialize crypto keys at startup\n");
2214 printf(" -I Enable internal timing if Zaptel timer is available\n");
2215 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2216 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2217 printf(" -m Mute the console from debugging and verbose output\n");
2218 printf(" -n Disable console colorization\n");
2219 printf(" -p Run as pseudo-realtime thread\n");
2220 printf(" -q Quiet mode (suppress output)\n");
2221 printf(" -r Connect to Asterisk on this machine\n");
2222 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2223 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2224 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2225 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2226 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2227 printf("\n");
2228 return 0;
2231 static void ast_readconfig(void)
2233 struct ast_config *cfg;
2234 struct ast_variable *v;
2235 char *config = AST_CONFIG_FILE;
2237 if (ast_opt_override_config) {
2238 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2239 if (!cfg)
2240 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2241 } else {
2242 cfg = ast_config_load(config);
2245 /* init with buildtime config */
2246 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2247 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2248 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2249 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2250 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2251 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2252 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2253 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2254 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2255 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2256 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2257 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2258 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2260 /* no asterisk.conf? no problem, use buildtime config! */
2261 if (!cfg) {
2262 return;
2265 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2266 if (!strcasecmp(v->name, "astctlpermissions")) {
2267 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2268 } else if (!strcasecmp(v->name, "astctlowner")) {
2269 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2270 } else if (!strcasecmp(v->name, "astctlgroup")) {
2271 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2272 } else if (!strcasecmp(v->name, "astctl")) {
2273 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2277 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2278 if (!strcasecmp(v->name, "astetcdir")) {
2279 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2280 } else if (!strcasecmp(v->name, "astspooldir")) {
2281 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2282 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2283 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2284 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2285 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2286 } else if (!strcasecmp(v->name, "astdatadir")) {
2287 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2288 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2289 } else if (!strcasecmp(v->name, "astlogdir")) {
2290 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2291 } else if (!strcasecmp(v->name, "astagidir")) {
2292 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2293 } else if (!strcasecmp(v->name, "astrundir")) {
2294 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2295 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2296 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2297 } else if (!strcasecmp(v->name, "astmoddir")) {
2298 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2302 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2303 /* verbose level (-v at startup) */
2304 if (!strcasecmp(v->name, "verbose")) {
2305 option_verbose = atoi(v->value);
2306 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2307 } else if (!strcasecmp(v->name, "timestamp")) {
2308 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2309 /* whether or not to support #exec in config files */
2310 } else if (!strcasecmp(v->name, "execincludes")) {
2311 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2312 /* debug level (-d at startup) */
2313 } else if (!strcasecmp(v->name, "debug")) {
2314 option_debug = 0;
2315 if (sscanf(v->value, "%d", &option_debug) != 1) {
2316 option_debug = ast_true(v->value);
2318 #if HAVE_WORKING_FORK
2319 /* Disable forking (-f at startup) */
2320 } else if (!strcasecmp(v->name, "nofork")) {
2321 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2322 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2323 } else if (!strcasecmp(v->name, "alwaysfork")) {
2324 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2325 #endif
2326 /* Run quietly (-q at startup ) */
2327 } else if (!strcasecmp(v->name, "quiet")) {
2328 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2329 /* Run as console (-c at startup, implies nofork) */
2330 } else if (!strcasecmp(v->name, "console")) {
2331 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2332 /* Run with high priority if the O/S permits (-p at startup) */
2333 } else if (!strcasecmp(v->name, "highpriority")) {
2334 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2335 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2336 } else if (!strcasecmp(v->name, "initcrypto")) {
2337 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2338 /* Disable ANSI colors for console (-c at startup) */
2339 } else if (!strcasecmp(v->name, "nocolor")) {
2340 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2341 /* Disable some usage warnings for picky people :p */
2342 } else if (!strcasecmp(v->name, "dontwarn")) {
2343 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2344 /* Dump core in case of crash (-g) */
2345 } else if (!strcasecmp(v->name, "dumpcore")) {
2346 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2347 /* Cache recorded sound files to another directory during recording */
2348 } else if (!strcasecmp(v->name, "cache_record_files")) {
2349 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2350 /* Specify cache directory */
2351 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2352 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2353 /* Build transcode paths via SLINEAR, instead of directly */
2354 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2355 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2356 /* Transmit SLINEAR silence while a channel is being recorded */
2357 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2358 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2359 /* Enable internal timing */
2360 } else if (!strcasecmp(v->name, "internal_timing")) {
2361 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2362 } else if (!strcasecmp(v->name, "maxcalls")) {
2363 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2364 option_maxcalls = 0;
2366 } else if (!strcasecmp(v->name, "maxload")) {
2367 double test[1];
2369 if (getloadavg(test, 1) == -1) {
2370 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2371 option_maxload = 0.0;
2372 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2373 option_maxload = 0.0;
2375 /* What user to run as */
2376 } else if (!strcasecmp(v->name, "runuser")) {
2377 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2378 /* What group to run as */
2379 } else if (!strcasecmp(v->name, "rungroup")) {
2380 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2381 } else if (!strcasecmp(v->name, "systemname")) {
2382 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2383 } else if (!strcasecmp(v->name, "languageprefix")) {
2384 ast_language_is_prefix = ast_true(v->value);
2387 ast_config_destroy(cfg);
2390 int main(int argc, char *argv[])
2392 int c;
2393 char filename[80] = "";
2394 char hostname[MAXHOSTNAMELEN] = "";
2395 char tmp[80];
2396 char * xarg = NULL;
2397 int x;
2398 FILE *f;
2399 sigset_t sigs;
2400 int num;
2401 int is_child_of_nonroot = 0;
2402 char *buf;
2403 char *runuser = NULL, *rungroup = NULL;
2405 /* Remember original args for restart */
2406 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2407 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2408 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2410 for (x=0; x<argc; x++)
2411 _argv[x] = argv[x];
2412 _argv[x] = NULL;
2414 /* if the progname is rasterisk consider it a remote console */
2415 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2416 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2418 if (gethostname(hostname, sizeof(hostname)-1))
2419 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2420 ast_mainpid = getpid();
2421 ast_ulaw_init();
2422 ast_alaw_init();
2423 callerid_init();
2424 ast_builtins_init();
2425 ast_utils_init();
2426 tdd_init();
2427 /* When Asterisk restarts after it has dropped the root privileges,
2428 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2430 if (getenv("ASTERISK_ALREADY_NONROOT"))
2431 is_child_of_nonroot=1;
2432 if (getenv("HOME"))
2433 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2434 /* Check for options */
2435 while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2436 switch (c) {
2437 #if HAVE_WORKING_FORK
2438 case 'F':
2439 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2440 break;
2441 case 'f':
2442 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2443 break;
2444 #endif
2445 case 'd':
2446 option_debug++;
2447 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2448 break;
2449 case 'c':
2450 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2451 break;
2452 case 'n':
2453 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2454 break;
2455 case 'r':
2456 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2457 break;
2458 case 'R':
2459 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2460 break;
2461 case 'p':
2462 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2463 break;
2464 case 'v':
2465 option_verbose++;
2466 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2467 break;
2468 case 'm':
2469 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2470 break;
2471 case 'M':
2472 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2473 option_maxcalls = 0;
2474 break;
2475 case 'L':
2476 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2477 option_maxload = 0.0;
2478 break;
2479 case 'q':
2480 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2481 break;
2482 case 't':
2483 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2484 break;
2485 case 'T':
2486 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2487 break;
2488 case 'x':
2489 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2490 xarg = optarg;
2491 break;
2492 case 'C':
2493 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2494 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2495 break;
2496 case 'I':
2497 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2498 break;
2499 case 'i':
2500 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2501 break;
2502 case 'g':
2503 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2504 break;
2505 case 'h':
2506 show_cli_help();
2507 exit(0);
2508 case 'V':
2509 show_version();
2510 exit(0);
2511 case 'U':
2512 runuser = optarg;
2513 break;
2514 case 'G':
2515 rungroup = optarg;
2516 break;
2517 case '?':
2518 exit(1);
2522 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2523 ast_register_verbose(console_verboser);
2524 WELCOME_MESSAGE;
2527 if (ast_opt_console && !option_verbose)
2528 ast_verbose("[ Booting...\n");
2530 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2531 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2532 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2535 /* For remote connections, change the name of the remote connection.
2536 * We do this for the benefit of init scripts (which need to know if/when
2537 * the main asterisk process has died yet). */
2538 if (ast_opt_remote) {
2539 strcpy(argv[0], "rasterisk");
2540 for (x = 1; x < argc; x++) {
2541 argv[x] = argv[0] + 10;
2545 if (ast_opt_console && !option_verbose)
2546 ast_verbose("[ Reading Master Configuration ]\n");
2547 ast_readconfig();
2549 if (ast_opt_dump_core) {
2550 struct rlimit l;
2551 memset(&l, 0, sizeof(l));
2552 l.rlim_cur = RLIM_INFINITY;
2553 l.rlim_max = RLIM_INFINITY;
2554 if (setrlimit(RLIMIT_CORE, &l)) {
2555 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2559 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2560 rungroup = ast_config_AST_RUN_GROUP;
2561 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2562 runuser = ast_config_AST_RUN_USER;
2564 #ifndef __CYGWIN__
2566 if (!is_child_of_nonroot)
2567 ast_set_priority(ast_opt_high_priority);
2569 if (!is_child_of_nonroot && rungroup) {
2570 struct group *gr;
2571 gr = getgrnam(rungroup);
2572 if (!gr) {
2573 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2574 exit(1);
2576 if (setgid(gr->gr_gid)) {
2577 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2578 exit(1);
2580 if (setgroups(0, NULL)) {
2581 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2582 exit(1);
2584 if (option_verbose)
2585 ast_verbose("Running as group '%s'\n", rungroup);
2588 if (!is_child_of_nonroot && runuser) {
2589 struct passwd *pw;
2590 pw = getpwnam(runuser);
2591 if (!pw) {
2592 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2593 exit(1);
2595 if (!rungroup) {
2596 if (setgid(pw->pw_gid)) {
2597 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2598 exit(1);
2600 if (initgroups(pw->pw_name, pw->pw_gid)) {
2601 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2602 exit(1);
2605 if (setuid(pw->pw_uid)) {
2606 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2607 exit(1);
2609 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2610 if (option_verbose)
2611 ast_verbose("Running as user '%s'\n", runuser);
2614 #endif /* __CYGWIN__ */
2616 #ifdef linux
2617 if (geteuid() && ast_opt_dump_core) {
2618 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2619 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2622 #endif
2624 ast_term_init();
2625 printf(term_end());
2626 fflush(stdout);
2628 if (ast_opt_console && !option_verbose)
2629 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2630 /* custom config setup */
2631 register_config_cli();
2632 read_config_maps();
2634 if (ast_opt_console) {
2635 if (el_hist == NULL || el == NULL)
2636 ast_el_initialize();
2638 if (!ast_strlen_zero(filename))
2639 ast_el_read_history(filename);
2642 if (ast_tryconnect()) {
2643 /* One is already running */
2644 if (ast_opt_remote) {
2645 if (ast_opt_exec) {
2646 ast_remotecontrol(xarg);
2647 quit_handler(0, 0, 0, 0);
2648 exit(0);
2650 printf(term_quit());
2651 ast_remotecontrol(NULL);
2652 quit_handler(0, 0, 0, 0);
2653 exit(0);
2654 } else {
2655 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2656 printf(term_quit());
2657 exit(1);
2659 } else if (ast_opt_remote || ast_opt_exec) {
2660 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2661 printf(term_quit());
2662 exit(1);
2664 /* Blindly write pid file since we couldn't connect */
2665 unlink(ast_config_AST_PID);
2666 f = fopen(ast_config_AST_PID, "w");
2667 if (f) {
2668 fprintf(f, "%ld\n", (long)getpid());
2669 fclose(f);
2670 } else
2671 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2673 #if HAVE_WORKING_FORK
2674 if (ast_opt_always_fork || !ast_opt_no_fork) {
2675 daemon(0, 0);
2676 ast_mainpid = getpid();
2677 /* Blindly re-write pid file since we are forking */
2678 unlink(ast_config_AST_PID);
2679 f = fopen(ast_config_AST_PID, "w");
2680 if (f) {
2681 fprintf(f, "%ld\n", (long)ast_mainpid);
2682 fclose(f);
2683 } else
2684 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2686 #endif
2688 /* Test recursive mutex locking. */
2689 if (test_for_thread_safety())
2690 ast_verbose("Warning! Asterisk is not thread safe.\n");
2692 ast_makesocket();
2693 sigemptyset(&sigs);
2694 sigaddset(&sigs, SIGHUP);
2695 sigaddset(&sigs, SIGTERM);
2696 sigaddset(&sigs, SIGINT);
2697 sigaddset(&sigs, SIGPIPE);
2698 sigaddset(&sigs, SIGWINCH);
2699 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2700 signal(SIGURG, urg_handler);
2701 signal(SIGINT, __quit_handler);
2702 signal(SIGTERM, __quit_handler);
2703 signal(SIGHUP, hup_handler);
2704 signal(SIGCHLD, child_handler);
2705 signal(SIGPIPE, SIG_IGN);
2707 /* ensure that the random number generators are seeded with a different value every time
2708 Asterisk is started
2710 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2711 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2713 if (init_logger()) {
2714 printf(term_quit());
2715 exit(1);
2717 if (load_modules(1)) {
2718 printf(term_quit());
2719 exit(1);
2722 if (dnsmgr_init()) {
2723 printf(term_quit());
2724 exit(1);
2727 ast_http_init();
2729 ast_channels_init();
2731 if (init_manager()) {
2732 printf(term_quit());
2733 exit(1);
2736 if (ast_cdr_engine_init()) {
2737 printf(term_quit());
2738 exit(1);
2741 if (ast_device_state_engine_init()) {
2742 printf(term_quit());
2743 exit(1);
2746 ast_rtp_init();
2748 ast_udptl_init();
2750 if (ast_image_init()) {
2751 printf(term_quit());
2752 exit(1);
2755 if (ast_file_init()) {
2756 printf(term_quit());
2757 exit(1);
2760 if (load_pbx()) {
2761 printf(term_quit());
2762 exit(1);
2765 if (init_framer()) {
2766 printf(term_quit());
2767 exit(1);
2770 if (astdb_init()) {
2771 printf(term_quit());
2772 exit(1);
2775 if (ast_enum_init()) {
2776 printf(term_quit());
2777 exit(1);
2780 if (load_modules(0)) {
2781 printf(term_quit());
2782 exit(1);
2785 dnsmgr_start_refresh();
2787 /* We might have the option of showing a console, but for now just
2788 do nothing... */
2789 if (ast_opt_console && !option_verbose)
2790 ast_verbose(" ]\n");
2791 if (option_verbose || ast_opt_console)
2792 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2793 if (ast_opt_no_fork)
2794 consolethread = pthread_self();
2796 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2797 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2799 #ifdef __AST_DEBUG_MALLOC
2800 __ast_mm_init();
2801 #endif
2803 time(&ast_startuptime);
2804 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
2806 if (ast_opt_console) {
2807 /* Console stuff now... */
2808 /* Register our quit function */
2809 char title[256];
2810 set_icon("Asterisk");
2811 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2812 set_title(title);
2814 for (;;) {
2815 buf = (char *)el_gets(el, &num);
2816 if (buf) {
2817 if (buf[strlen(buf)-1] == '\n')
2818 buf[strlen(buf)-1] = '\0';
2820 consolehandler((char *)buf);
2821 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2822 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
2823 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2824 int fd;
2825 fd = open("/dev/null", O_RDWR);
2826 if (fd > -1) {
2827 dup2(fd, STDOUT_FILENO);
2828 dup2(fd, STDIN_FILENO);
2829 } else
2830 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2831 break;
2836 /* Do nothing */
2837 for (;;) { /* apparently needed for Mac OS X */
2838 struct pollfd p = { -1 /* no descriptor */, 0, 0 };
2840 poll(&p, 0, -1);
2843 return 0;