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 */
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
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
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
71 #include <sys/socket.h>
77 #include <sys/resource.h>
82 #include <sys/prctl.h>
87 #include <sys/prctl.h>
90 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
93 int daemon(int, int); /* defined in libresolv of all places */
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"
131 #define AF_LOCAL AF_UNIX
132 #define PF_LOCAL PF_UNIX
135 #define AST_MAX_CONNECTS 128
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 '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 'show license' for details.\n"); \
146 ast_verbose("=========================================================================\n")
148 /*! \defgroup main_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
155 extern int ast_language_is_prefix; /* XXX move to some header */
157 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
159 int option_verbose = 0; /*!< Verbosity level */
160 int option_debug = 0; /*!< Debug level */
162 double option_maxload = 0.0; /*!< Max load avg on system */
163 int option_maxcalls = 0; /*!< Max number of active calls */
167 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
168 char debug_filename[AST_FILENAME_MAX] = "";
170 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
171 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
174 int fd; /*!< File descriptor */
175 int p[2]; /*!< Pipe */
176 pthread_t t; /*!< Thread of handler */
177 int mute; /*!< Is the console muted for logs */
182 AST_LIST_ENTRY(ast_atexit) list;
185 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
187 time_t ast_startuptime;
188 time_t ast_lastreloadtime;
190 static History *el_hist = NULL;
191 static EditLine *el = NULL;
192 static char *remotehostname;
194 struct console consoles[AST_MAX_CONNECTS];
196 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
198 static int ast_el_add_history(char *);
199 static int ast_el_read_history(char *);
200 static int ast_el_write_history(char *);
202 char ast_config_AST_CONFIG_DIR[PATH_MAX];
203 char ast_config_AST_CONFIG_FILE[PATH_MAX];
204 char ast_config_AST_MODULE_DIR[PATH_MAX];
205 char ast_config_AST_SPOOL_DIR[PATH_MAX];
206 char ast_config_AST_MONITOR_DIR[PATH_MAX];
207 char ast_config_AST_VAR_DIR[PATH_MAX];
208 char ast_config_AST_DATA_DIR[PATH_MAX];
209 char ast_config_AST_LOG_DIR[PATH_MAX];
210 char ast_config_AST_AGI_DIR[PATH_MAX];
211 char ast_config_AST_DB[PATH_MAX];
212 char ast_config_AST_KEY_DIR[PATH_MAX];
213 char ast_config_AST_PID[PATH_MAX];
214 char ast_config_AST_SOCKET[PATH_MAX];
215 char ast_config_AST_RUN_DIR[PATH_MAX];
216 char ast_config_AST_RUN_USER[PATH_MAX];
217 char ast_config_AST_RUN_GROUP[PATH_MAX];
218 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
219 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
220 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
221 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
222 char ast_config_AST_SYSTEM_NAME[20] = "";
224 extern const char *ast_build_hostname;
225 extern const char *ast_build_kernel;
226 extern const char *ast_build_machine;
227 extern const char *ast_build_os;
228 extern const char *ast_build_date;
229 extern const char *ast_build_user;
231 static char *_argv[256];
232 static int shuttingdown = 0;
233 static int restartnow = 0;
234 static pthread_t consolethread = AST_PTHREADT_NULL;
236 static char randompool[256];
238 #if !defined(LOW_MEMORY)
239 struct file_version {
240 AST_LIST_ENTRY(file_version) list;
245 static AST_LIST_HEAD_STATIC(file_versions, file_version);
247 void ast_register_file_version(const char *file, const char *version)
249 struct file_version *new;
251 size_t version_length;
253 work = ast_strdupa(version);
254 work = ast_strip(ast_strip_quoted(work, "$", "$"));
255 version_length = strlen(work) + 1;
257 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
261 new->version = (char *) new + sizeof(*new);
262 memcpy(new->version, work, version_length);
263 AST_LIST_LOCK(&file_versions);
264 AST_LIST_INSERT_HEAD(&file_versions, new, list);
265 AST_LIST_UNLOCK(&file_versions);
268 void ast_unregister_file_version(const char *file)
270 struct file_version *find;
272 AST_LIST_LOCK(&file_versions);
273 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
274 if (!strcasecmp(find->file, file)) {
275 AST_LIST_REMOVE_CURRENT(&file_versions, list);
279 AST_LIST_TRAVERSE_SAFE_END;
280 AST_LIST_UNLOCK(&file_versions);
285 struct thread_list_t {
286 AST_LIST_ENTRY(thread_list_t) list;
291 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
293 static char show_threads_help[] =
294 "Usage: show threads\n"
295 " List threads currently active in the system.\n";
297 void ast_register_thread(char *name)
299 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
303 new->id = pthread_self();
304 new->name = name; /* this was a copy already */
305 AST_LIST_LOCK(&thread_list);
306 AST_LIST_INSERT_HEAD(&thread_list, new, list);
307 AST_LIST_UNLOCK(&thread_list);
310 void ast_unregister_thread(void *id)
312 struct thread_list_t *x;
314 AST_LIST_LOCK(&thread_list);
315 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
316 if ((void *)x->id == id) {
317 AST_LIST_REMOVE_CURRENT(&thread_list, list);
321 AST_LIST_TRAVERSE_SAFE_END;
322 AST_LIST_UNLOCK(&thread_list);
329 static int handle_show_threads(int fd, int argc, char *argv[])
332 struct thread_list_t *cur;
334 AST_LIST_LOCK(&thread_list);
335 AST_LIST_TRAVERSE(&thread_list, cur, list) {
336 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
339 AST_LIST_UNLOCK(&thread_list);
340 ast_cli(fd, "%d threads listed.\n", count);
344 struct profile_entry {
346 uint64_t scale; /* if non-zero, values are scaled by this */
352 struct profile_data {
355 struct profile_entry e[0];
358 static struct profile_data *prof_data;
360 /*! \brief allocates a counter with a given name and scale.
361 * \return Returns the identifier of the counter.
363 int ast_add_profile(const char *name, uint64_t scale)
365 int l = sizeof(struct profile_data);
366 int n = 10; /* default entries */
368 if (prof_data == NULL) {
369 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
370 if (prof_data == NULL)
372 prof_data->entries = 0;
373 prof_data->max_size = n;
375 if (prof_data->entries >= prof_data->max_size) {
377 n = prof_data->max_size + 20;
378 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
382 prof_data->max_size = n;
384 n = prof_data->entries++;
385 prof_data->e[n].name = ast_strdup(name);
386 prof_data->e[n].value = 0;
387 prof_data->e[n].events = 0;
388 prof_data->e[n].mark = 0;
389 prof_data->e[n].scale = scale;
393 int64_t ast_profile(int i, int64_t delta)
395 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
397 if (prof_data->e[i].scale > 1)
398 delta /= prof_data->e[i].scale;
399 prof_data->e[i].value += delta;
400 prof_data->e[i].events++;
401 return prof_data->e[i].value;
404 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
405 #if defined(__FreeBSD__)
406 #include <machine/cpufunc.h>
408 static __inline u_int64_t
413 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
417 #else /* supply a dummy function on other platforms */
418 static __inline u_int64_t
425 int64_t ast_mark(int i, int startstop)
427 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
430 prof_data->e[i].mark = rdtsc();
432 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
433 if (prof_data->e[i].scale > 1)
434 prof_data->e[i].mark /= prof_data->e[i].scale;
435 prof_data->e[i].value += prof_data->e[i].mark;
436 prof_data->e[i].events++;
438 return prof_data->e[i].mark;
441 static int handle_show_profile(int fd, int argc, char *argv[])
446 if (prof_data == NULL)
450 max = prof_data->entries;
451 if (argc >= 3) { /* specific entries */
452 if (isdigit(argv[2][0])) {
454 if (argc == 4 && strcmp(argv[3], "-"))
459 if (max > prof_data->entries)
460 max = prof_data->entries;
461 if (!strcmp(argv[0], "clear")) {
462 for (i= min; i < max; i++) {
463 if (!search || strstr(prof_data->e[i].name, search)) {
464 prof_data->e[i].value = 0;
465 prof_data->e[i].events = 0;
470 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
471 prof_data->entries, prof_data->max_size);
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",
478 (long)e->events, (long long)e->value,
479 (long long)(e->events ? e->value / e->events : e->value),
485 static char show_version_files_help[] =
486 "Usage: show version files [like <pattern>]\n"
487 " Shows the revision numbers of the files used to build this copy of Asterisk.\n"
488 " Optional regular expression pattern is used to filter the file list.\n";
490 /*! \brief CLI command to list module versions */
491 static int handle_show_version_files(int fd, int argc, char *argv[])
493 #define FORMAT "%-25.25s %-40.40s\n"
494 struct file_version *iterator;
502 if (!strcasecmp(argv[3], "like")) {
503 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
504 return RESULT_SHOWUSAGE;
507 return RESULT_SHOWUSAGE;
515 return RESULT_SHOWUSAGE;
518 ast_cli(fd, FORMAT, "File", "Revision");
519 ast_cli(fd, FORMAT, "----", "--------");
520 AST_LIST_LOCK(&file_versions);
521 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
522 if (havename && strcasecmp(iterator->file, argv[3]))
525 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
528 ast_cli(fd, FORMAT, iterator->file, iterator->version);
533 AST_LIST_UNLOCK(&file_versions);
535 ast_cli(fd, "%d files listed.\n", count_files);
541 return RESULT_SUCCESS;
545 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
547 struct file_version *find;
550 int matchlen = strlen(word);
555 AST_LIST_LOCK(&file_versions);
556 AST_LIST_TRAVERSE(&file_versions, find, list) {
557 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
558 ret = ast_strdup(find->file);
562 AST_LIST_UNLOCK(&file_versions);
566 #endif /* ! LOW_MEMORY */
568 int ast_register_atexit(void (*func)(void))
571 struct ast_atexit *ae;
572 ast_unregister_atexit(func);
573 AST_LIST_LOCK(&atexits);
574 if ((ae = ast_calloc(1, sizeof(*ae)))) {
575 AST_LIST_INSERT_HEAD(&atexits, ae, list);
579 AST_LIST_UNLOCK(&atexits);
583 void ast_unregister_atexit(void (*func)(void))
585 struct ast_atexit *ae;
586 AST_LIST_LOCK(&atexits);
587 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
588 if (ae->func == func) {
589 AST_LIST_REMOVE_CURRENT(&atexits, list);
593 AST_LIST_TRAVERSE_SAFE_END
594 AST_LIST_UNLOCK(&atexits);
597 static int fdprint(int fd, const char *s)
599 return write(fd, s, strlen(s) + 1);
602 /*! \brief NULL handler so we can collect the child exit status */
603 static void null_sig_handler(int signal)
608 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
609 /*! \brief Keep track of how many threads are currently trying to wait*() on
611 static unsigned int safe_system_level = 0;
612 static void *safe_system_prev_handler;
614 void ast_replace_sigchld(void)
618 ast_mutex_lock(&safe_system_lock);
619 level = safe_system_level++;
621 /* only replace the handler if it has not already been done */
623 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
625 ast_mutex_unlock(&safe_system_lock);
628 void ast_unreplace_sigchld(void)
632 ast_mutex_lock(&safe_system_lock);
633 level = --safe_system_level;
635 /* only restore the handler if we are the last one */
637 signal(SIGCHLD, safe_system_prev_handler);
639 ast_mutex_unlock(&safe_system_lock);
642 int ast_safe_system(const char *s)
647 struct rusage rusage;
650 #if HAVE_WORKING_FORK
651 ast_replace_sigchld();
656 if (ast_opt_high_priority)
658 /* Close file descriptors and launch system command */
659 for (x = STDERR_FILENO + 1; x < 4096; x++)
661 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
663 } else if (pid > 0) {
665 res = wait4(pid, &status, 0, &rusage);
667 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
669 } else if (errno != EINTR)
673 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
677 ast_unreplace_sigchld();
686 * \brief mute or unmute a console from logging
688 void ast_console_toggle_mute(int fd) {
690 for (x = 0;x < AST_MAX_CONNECTS; x++) {
691 if (fd == consoles[x].fd) {
692 if (consoles[x].mute) {
693 consoles[x].mute = 0;
694 ast_cli(fd, "Console is not muted anymore.\n");
696 consoles[x].mute = 1;
697 ast_cli(fd, "Console is muted.\n");
702 ast_cli(fd, "Couldn't find remote console.\n");
706 * \brief log the string to all attached console clients
708 static void ast_network_puts_mutable(const char *string)
711 for (x = 0;x < AST_MAX_CONNECTS; x++) {
712 if (consoles[x].mute)
714 if (consoles[x].fd > -1)
715 fdprint(consoles[x].p[1], string);
720 * \brief log the string to the console, and all attached
723 void ast_console_puts_mutable(const char *string)
725 fputs(string, stdout);
727 ast_network_puts_mutable(string);
731 * \brief write the string to all attached console clients
733 static void ast_network_puts(const char *string)
736 for (x=0; x < AST_MAX_CONNECTS; x++) {
737 if (consoles[x].fd > -1)
738 fdprint(consoles[x].p[1], string);
743 * write the string to the console, and all attached
746 void ast_console_puts(const char *string)
748 fputs(string, stdout);
750 ast_network_puts(string);
753 static void network_verboser(const char *s)
755 ast_network_puts_mutable(s);
758 static pthread_t lthread;
760 static void *netconsole(void *vconsole)
762 struct console *con = vconsole;
763 char hostname[MAXHOSTNAMELEN] = "";
766 struct pollfd fds[2];
768 if (gethostname(hostname, sizeof(hostname)-1))
769 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
770 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
771 fdprint(con->fd, tmp);
774 fds[0].events = POLLIN;
776 fds[1].fd = con->p[0];
777 fds[1].events = POLLIN;
780 res = poll(fds, 2, -1);
783 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
786 if (fds[0].revents) {
787 res = read(con->fd, tmp, sizeof(tmp));
792 ast_cli_command(con->fd, tmp);
794 if (fds[1].revents) {
795 res = read(con->p[0], tmp, sizeof(tmp));
797 ast_log(LOG_ERROR, "read returned %d\n", res);
800 res = write(con->fd, tmp, res);
805 if (option_verbose > 2)
806 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
815 static void *listener(void *unused)
817 struct sockaddr_un sunaddr;
822 struct pollfd fds[1];
824 pthread_attr_init(&attr);
825 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
829 fds[0].fd = ast_socket;
830 fds[0].events = POLLIN;
831 s = poll(fds, 1, -1);
832 pthread_testcancel();
835 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
838 len = sizeof(sunaddr);
839 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
842 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
844 for (x = 0; x < AST_MAX_CONNECTS; x++) {
845 if (consoles[x].fd < 0) {
846 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
847 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
849 fdprint(s, "Server failed to create pipe\n");
853 flags = fcntl(consoles[x].p[1], F_GETFL);
854 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
856 consoles[x].mute = ast_opt_mute;
857 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
858 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
859 close(consoles[x].p[0]);
860 close(consoles[x].p[1]);
862 fdprint(s, "Server failed to spawn thread\n");
868 if (x >= AST_MAX_CONNECTS) {
869 fdprint(s, "No more connections allowed\n");
870 ast_log(LOG_WARNING, "No more connections allowed\n");
872 } else if (consoles[x].fd > -1) {
873 if (option_verbose > 2)
874 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
881 static int ast_makesocket(void)
883 struct sockaddr_un sunaddr;
889 for (x = 0; x < AST_MAX_CONNECTS; x++)
891 unlink(ast_config_AST_SOCKET);
892 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
893 if (ast_socket < 0) {
894 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
897 memset(&sunaddr, 0, sizeof(sunaddr));
898 sunaddr.sun_family = AF_LOCAL;
899 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
900 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
902 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
907 res = listen(ast_socket, 2);
909 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
914 ast_register_verbose(network_verboser);
915 ast_pthread_create(<hread, NULL, listener, NULL);
917 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
919 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
920 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
926 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
928 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
929 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
935 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
936 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
938 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
941 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
943 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
944 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
950 static int ast_tryconnect(void)
952 struct sockaddr_un sunaddr;
954 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
955 if (ast_consock < 0) {
956 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
959 memset(&sunaddr, 0, sizeof(sunaddr));
960 sunaddr.sun_family = AF_LOCAL;
961 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
962 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
971 /*! \brief Urgent handler
973 Called by soft_hangup to interrupt the poll, read, or other
974 system call. We don't actually need to do anything though.
975 Remember: Cannot EVER ast_log from within a signal handler
977 static void urg_handler(int num)
979 signal(num, urg_handler);
983 static void hup_handler(int num)
985 if (option_verbose > 1)
986 printf("Received HUP signal -- Reloading configs\n");
988 execvp(_argv[0], _argv);
989 /* XXX This could deadlock XXX */
990 ast_module_reload(NULL);
991 signal(num, hup_handler);
994 static void child_handler(int sig)
996 /* Must not ever ast_log or ast_verbose within signal handler */
1000 * Reap all dead children -- not just one
1002 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1004 if (n == 0 && option_debug)
1005 printf("Huh? Child handler, but nobody there?\n");
1006 signal(sig, child_handler);
1009 /*! \brief Set an X-term or screen title */
1010 static void set_title(char *text)
1012 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1013 fprintf(stdout, "\033]2;%s\007", text);
1016 static void set_icon(char *text)
1018 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1019 fprintf(stdout, "\033]1;%s\007", text);
1022 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1023 else. If your PBX has heavy activity on it, this is a good thing. */
1024 int ast_set_priority(int pri)
1026 struct sched_param sched;
1027 memset(&sched, 0, sizeof(sched));
1030 sched.sched_priority = 10;
1031 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1032 ast_log(LOG_WARNING, "Unable to set high priority\n");
1036 ast_verbose("Set to realtime thread\n");
1038 sched.sched_priority = 0;
1039 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
1040 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1046 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1047 ast_log(LOG_WARNING, "Unable to set high priority\n");
1051 ast_verbose("Set to high priority\n");
1053 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1054 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1062 static void ast_run_atexits(void)
1064 struct ast_atexit *ae;
1065 AST_LIST_LOCK(&atexits);
1066 AST_LIST_TRAVERSE(&atexits, ae, list) {
1070 AST_LIST_UNLOCK(&atexits);
1073 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1075 char filename[80] = "";
1078 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1079 ast_cdr_engine_term();
1083 /* Begin shutdown routine, hanging up active channels */
1084 ast_begin_shutdown(1);
1085 if (option_verbose && ast_opt_console)
1086 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1090 /* Wait up to 15 seconds for all channels to go away */
1093 if (!ast_active_channels())
1097 /* Sleep 1/10 of a second */
1102 ast_begin_shutdown(0);
1103 if (option_verbose && ast_opt_console)
1104 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1106 if (!ast_active_channels())
1114 if (!shuttingdown) {
1115 if (option_verbose && ast_opt_console)
1116 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1120 if (ast_opt_console || ast_opt_remote) {
1122 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1123 if (!ast_strlen_zero(filename))
1124 ast_el_write_history(filename);
1127 if (el_hist != NULL)
1128 history_end(el_hist);
1131 ast_verbose("Executing last minute cleanups\n");
1133 /* Called on exit */
1134 if (option_verbose && ast_opt_console)
1135 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1136 else if (option_debug)
1137 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1138 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1139 if (ast_socket > -1) {
1140 pthread_cancel(lthread);
1143 unlink(ast_config_AST_SOCKET);
1145 if (ast_consock > -1)
1147 if (!ast_opt_remote)
1148 unlink(ast_config_AST_PID);
1149 printf(term_quit());
1151 if (option_verbose || ast_opt_console)
1152 ast_verbose("Preparing for Asterisk restart...\n");
1153 /* Mark all FD's for closing on exec */
1154 for (x=3; x < 32768; x++) {
1155 fcntl(x, F_SETFD, FD_CLOEXEC);
1157 if (option_verbose || ast_opt_console)
1158 ast_verbose("Restarting Asterisk NOW...\n");
1164 /* If there is a consolethread running send it a SIGHUP
1165 so it can execvp, otherwise we can do it ourselves */
1166 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1167 pthread_kill(consolethread, SIGHUP);
1168 /* Give the signal handler some time to complete */
1171 execvp(_argv[0], _argv);
1180 static void __quit_handler(int num)
1182 quit_handler(num, 0, 1, 0);
1185 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1188 if (!strncmp(s, cmp, strlen(cmp))) {
1189 c = s + strlen(cmp);
1190 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1196 static void console_verboser(const char *s)
1199 const char *c = NULL;
1201 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1202 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1203 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1204 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1212 /* Wake up a poll()ing console */
1213 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1214 pthread_kill(consolethread, SIGURG);
1217 static int ast_all_zeros(char *s)
1227 static void consolehandler(char *s)
1232 /* Called when readline data is available */
1233 if (!ast_all_zeros(s))
1234 ast_el_add_history(s);
1235 /* The real handler for bang */
1238 ast_safe_system(s+1);
1240 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1242 ast_cli_command(STDOUT_FILENO, s);
1245 static int remoteconsolehandler(char *s)
1249 /* Called when readline data is available */
1250 if (!ast_all_zeros(s))
1251 ast_el_add_history(s);
1252 /* The real handler for bang */
1255 ast_safe_system(s+1);
1257 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1260 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1261 (s[4] == '\0' || isspace(s[4]))) {
1262 quit_handler(0, 0, 0, 0);
1269 static char abort_halt_help[] =
1270 "Usage: abort shutdown\n"
1271 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1272 " call operations.\n";
1274 static char shutdown_now_help[] =
1276 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1278 static char shutdown_gracefully_help[] =
1279 "Usage: stop gracefully\n"
1280 " Causes Asterisk to not accept new calls, and exit when all\n"
1281 " active calls have terminated normally.\n";
1283 static char shutdown_when_convenient_help[] =
1284 "Usage: stop when convenient\n"
1285 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1287 static char restart_now_help[] =
1288 "Usage: restart now\n"
1289 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1292 static char restart_gracefully_help[] =
1293 "Usage: restart gracefully\n"
1294 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1295 " restart when all active calls have ended.\n";
1297 static char restart_when_convenient_help[] =
1298 "Usage: restart when convenient\n"
1299 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1301 static char bang_help[] =
1302 "Usage: !<command>\n"
1303 " Executes a given shell command\n";
1305 static char show_warranty_help[] =
1306 "Usage: show warranty\n"
1307 " Shows the warranty (if any) for this copy of Asterisk.\n";
1309 static char show_license_help[] =
1310 "Usage: show license\n"
1311 " Shows the license(s) for this copy of Asterisk.\n";
1313 static char version_help[] =
1314 "Usage: show version\n"
1315 " Shows Asterisk version information.\n";
1317 static int handle_version(int fd, int argc, char *argv[])
1320 return RESULT_SHOWUSAGE;
1321 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1322 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1323 ast_build_machine, ast_build_os, ast_build_date);
1324 return RESULT_SUCCESS;
1328 static int handle_quit(int fd, int argc, char *argv[])
1331 return RESULT_SHOWUSAGE;
1332 quit_handler(0, 0, 1, 0);
1333 return RESULT_SUCCESS;
1337 static int handle_shutdown_now(int fd, int argc, char *argv[])
1340 return RESULT_SHOWUSAGE;
1341 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1342 return RESULT_SUCCESS;
1345 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1348 return RESULT_SHOWUSAGE;
1349 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1350 return RESULT_SUCCESS;
1353 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1356 return RESULT_SHOWUSAGE;
1357 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1358 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1359 return RESULT_SUCCESS;
1362 static int handle_restart_now(int fd, int argc, char *argv[])
1365 return RESULT_SHOWUSAGE;
1366 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1367 return RESULT_SUCCESS;
1370 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1373 return RESULT_SHOWUSAGE;
1374 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1375 return RESULT_SUCCESS;
1378 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1381 return RESULT_SHOWUSAGE;
1382 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1383 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1384 return RESULT_SUCCESS;
1387 static int handle_abort_halt(int fd, int argc, char *argv[])
1390 return RESULT_SHOWUSAGE;
1391 ast_cancel_shutdown();
1393 return RESULT_SUCCESS;
1396 static int handle_bang(int fd, int argc, char *argv[])
1398 return RESULT_SUCCESS;
1400 static const char *warranty_lines[] = {
1404 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1405 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1406 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1407 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1408 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1409 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1410 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1411 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1412 "REPAIR OR CORRECTION.\n",
1414 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1415 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1416 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1417 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1418 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1419 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1420 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1421 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1422 "POSSIBILITY OF SUCH DAMAGES.\n",
1425 static int show_warranty(int fd, int argc, char *argv[])
1429 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1430 ast_cli(fd, (char *) warranty_lines[x]);
1432 return RESULT_SUCCESS;
1435 static const char *license_lines[] = {
1437 "This program is free software; you can redistribute it and/or modify\n",
1438 "it under the terms of the GNU General Public License version 2 as\n",
1439 "published by the Free Software Foundation.\n",
1441 "This program also contains components licensed under other licenses.\n",
1444 "This program is distributed in the hope that it will be useful,\n",
1445 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1446 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1447 "GNU General Public License for more details.\n",
1449 "You should have received a copy of the GNU General Public License\n",
1450 "along with this program; if not, write to the Free Software\n",
1451 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1454 static int show_license(int fd, int argc, char *argv[])
1458 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1459 ast_cli(fd, (char *) license_lines[x]);
1461 return RESULT_SUCCESS;
1464 #define ASTERISK_PROMPT "*CLI> "
1466 #define ASTERISK_PROMPT2 "%s*CLI> "
1468 static struct ast_cli_entry core_cli[] = {
1469 { { "abort", "halt", NULL }, handle_abort_halt,
1470 "Cancel a running halt", abort_halt_help },
1471 { { "stop", "now", NULL }, handle_shutdown_now,
1472 "Shut down Asterisk immediately", shutdown_now_help },
1473 { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1474 "Gracefully shut down Asterisk", shutdown_gracefully_help },
1475 { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1476 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1477 { { "restart", "now", NULL }, handle_restart_now,
1478 "Restart Asterisk immediately", restart_now_help },
1479 { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1480 "Restart Asterisk gracefully", restart_gracefully_help },
1481 { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1482 "Restart Asterisk at empty call volume", restart_when_convenient_help },
1483 { { "show", "warranty", NULL }, show_warranty,
1484 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
1485 { { "show", "license", NULL }, show_license,
1486 "Show the license(s) for this copy of Asterisk", show_license_help },
1487 { { "show", "version", NULL }, handle_version,
1488 "Display version info", version_help },
1489 { { "!", NULL }, handle_bang,
1490 "Execute a shell command", bang_help },
1491 #if !defined(LOW_MEMORY)
1492 { { "show", "version", "files", NULL }, handle_show_version_files,
1493 "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1494 { { "show", "threads", NULL }, handle_show_threads,
1495 "Show running threads", show_threads_help, NULL },
1496 { { "show", "profile", NULL }, handle_show_profile,
1497 "Show profiling info"},
1498 { { "clear", "profile", NULL }, handle_show_profile,
1499 "Clear profiling info"},
1500 #endif /* ! LOW_MEMORY */
1503 static int ast_el_read_char(EditLine *el, char *cp)
1507 struct pollfd fds[2];
1514 fds[0].fd = ast_consock;
1515 fds[0].events = POLLIN;
1516 if (!ast_opt_exec) {
1517 fds[1].fd = STDIN_FILENO;
1518 fds[1].events = POLLIN;
1521 res = poll(fds, max, -1);
1525 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1529 if (!ast_opt_exec && fds[1].revents) {
1530 num_read = read(STDIN_FILENO, cp, 1);
1536 if (fds[0].revents) {
1537 res = read(ast_consock, buf, sizeof(buf) - 1);
1538 /* if the remote side disappears exit */
1540 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1541 if (!ast_opt_reconnect) {
1542 quit_handler(0, 0, 0, 0);
1545 int reconnects_per_second = 20;
1546 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1547 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1548 if (ast_tryconnect()) {
1549 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1550 printf(term_quit());
1554 usleep(1000000 / reconnects_per_second);
1557 if (tries >= 30 * reconnects_per_second) {
1558 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1559 quit_handler(0, 0, 0, 0);
1566 if (!ast_opt_exec && !lastpos)
1567 write(STDOUT_FILENO, "\r", 1);
1568 write(STDOUT_FILENO, buf, res);
1569 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1582 static char *cli_prompt(EditLine *el)
1584 static char prompt[200];
1589 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1590 char *t = pfmt, *p = prompt;
1591 memset(prompt, 0, sizeof(prompt));
1592 while (*t != '\0' && *p < sizeof(prompt)) {
1594 char hostname[MAXHOSTNAMELEN]="";
1601 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1605 case 'C': /* color */
1607 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1608 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1610 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1611 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1615 /* If the color has been reset correctly, then there's no need to reset it later */
1616 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1622 case 'd': /* date */
1623 memset(&tm, 0, sizeof(tm));
1625 if (localtime_r(&ts, &tm)) {
1626 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1629 case 'h': /* hostname */
1630 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1631 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1633 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1636 case 'H': /* short hostname */
1637 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1638 for (i = 0; i < sizeof(hostname); i++) {
1639 if (hostname[i] == '.') {
1644 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1646 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1650 case 'l': /* load avg */
1652 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1653 float avg1, avg2, avg3;
1654 int actproc, totproc, npid, which;
1655 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1656 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1657 if (sscanf(t, "%d", &which) == 1) {
1660 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1663 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1666 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1669 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1672 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1679 case 's': /* Asterisk system name (from asterisk.conf) */
1680 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1682 case 't': /* time */
1683 memset(&tm, 0, sizeof(tm));
1685 if (localtime_r(&ts, &tm)) {
1686 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1689 case '#': /* process console or remote? */
1690 if (!ast_opt_remote) {
1691 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1693 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1696 case '%': /* literal % */
1697 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1699 case '\0': /* % is last character - prevent bug */
1703 while (*p != '\0') {
1714 /* Force colors back to normal at end */
1715 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1716 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1717 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1719 strncat(p, term_code, sizeof(term_code));
1722 } else if (remotehostname)
1723 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1725 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1730 static char **ast_el_strtoarr(char *buf)
1732 char **match_list = NULL, *retstr;
1733 size_t match_list_len;
1737 while ( (retstr = strsep(&buf, " ")) != NULL) {
1739 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1741 if (matches + 1 >= match_list_len) {
1742 match_list_len <<= 1;
1743 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1744 /* TODO: Handle memory allocation failure */
1748 match_list[matches++] = strdup(retstr);
1752 return (char **) NULL;
1754 if (matches >= match_list_len) {
1755 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1756 /* TODO: Handle memory allocation failure */
1760 match_list[matches] = (char *) NULL;
1765 static int ast_el_sort_compare(const void *i1, const void *i2)
1769 s1 = ((char **)i1)[0];
1770 s2 = ((char **)i2)[0];
1772 return strcasecmp(s1, s2);
1775 static int ast_cli_display_match_list(char **matches, int len, int max)
1777 int i, idx, limit, count;
1778 int screenwidth = 0;
1779 int numoutput = 0, numoutputline = 0;
1781 screenwidth = ast_get_termcols(STDOUT_FILENO);
1783 /* find out how many entries can be put on one line, with two spaces between strings */
1784 limit = screenwidth / (max + 2);
1788 /* how many lines of output */
1789 count = len / limit;
1790 if (count * limit < len)
1795 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1797 for (; count > 0; count--) {
1799 for (i=0; i < limit && matches[idx]; i++, idx++) {
1801 /* Don't print dupes */
1802 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1805 matches[idx] = NULL;
1811 fprintf(stdout, "%-*s ", max, matches[idx]);
1813 matches[idx] = NULL;
1815 if (numoutputline > 0)
1816 fprintf(stdout, "\n");
1823 static char *cli_complete(EditLine *el, int ch)
1829 int retval = CC_ERROR;
1833 LineInfo *lf = (LineInfo *)el_line(el);
1835 *(char *)lf->cursor = '\0';
1836 ptr = (char *)lf->cursor;
1838 while (ptr > lf->buffer) {
1839 if (isspace(*ptr)) {
1847 len = lf->cursor - ptr;
1849 if (ast_opt_remote) {
1850 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1851 fdprint(ast_consock, buf);
1852 res = read(ast_consock, buf, sizeof(buf));
1854 nummatches = atoi(buf);
1856 if (nummatches > 0) {
1858 int mlen = 0, maxmbuf = 2048;
1859 /* Start with a 2048 byte buffer */
1860 if (!(mbuf = ast_malloc(maxmbuf)))
1861 return (char *)(CC_ERROR);
1862 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1863 fdprint(ast_consock, buf);
1866 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1867 if (mlen + 1024 > maxmbuf) {
1868 /* Every step increment buffer 1024 bytes */
1870 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1871 return (char *)(CC_ERROR);
1873 /* Only read 1024 bytes at a time */
1874 res = read(ast_consock, mbuf + mlen, 1024);
1880 matches = ast_el_strtoarr(mbuf);
1883 matches = (char **) NULL;
1885 char **p, *oldbuf=NULL;
1887 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1888 for (p = matches; p && *p; p++) {
1889 if (!oldbuf || strcmp(*p,oldbuf))
1897 int matches_num, maxlen, match_len;
1899 if (matches[0][0] != '\0') {
1900 el_deletestr(el, (int) len);
1901 el_insertstr(el, matches[0]);
1902 retval = CC_REFRESH;
1905 if (nummatches == 1) {
1906 /* Found an exact match */
1907 el_insertstr(el, " ");
1908 retval = CC_REFRESH;
1910 /* Must be more than one match */
1911 for (i=1, maxlen=0; matches[i]; i++) {
1912 match_len = strlen(matches[i]);
1913 if (match_len > maxlen)
1916 matches_num = i - 1;
1917 if (matches_num >1) {
1918 fprintf(stdout, "\n");
1919 ast_cli_display_match_list(matches, nummatches, maxlen);
1920 retval = CC_REDISPLAY;
1922 el_insertstr(el," ");
1923 retval = CC_REFRESH;
1929 return (char *)(long)retval;
1932 static int ast_el_initialize(void)
1935 char *editor = getenv("AST_EDITOR");
1939 if (el_hist != NULL)
1940 history_end(el_hist);
1942 el = el_init("asterisk", stdin, stdout, stderr);
1943 el_set(el, EL_PROMPT, cli_prompt);
1945 el_set(el, EL_EDITMODE, 1);
1946 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1947 el_hist = history_init();
1948 if (!el || !el_hist)
1951 /* setup history with 100 entries */
1952 history(el_hist, &ev, H_SETSIZE, 100);
1954 el_set(el, EL_HIST, history, el_hist);
1956 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1957 /* Bind <tab> to command completion */
1958 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1959 /* Bind ? to command completion */
1960 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1961 /* Bind ^D to redisplay */
1962 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1967 static int ast_el_add_history(char *buf)
1971 if (el_hist == NULL || el == NULL)
1972 ast_el_initialize();
1973 if (strlen(buf) > 256)
1975 return (history(el_hist, &ev, H_ENTER, buf));
1978 static int ast_el_write_history(char *filename)
1982 if (el_hist == NULL || el == NULL)
1983 ast_el_initialize();
1985 return (history(el_hist, &ev, H_SAVE, filename));
1988 static int ast_el_read_history(char *filename)
1994 if (el_hist == NULL || el == NULL)
1995 ast_el_initialize();
1997 if ((f = fopen(filename, "r")) == NULL)
2001 fgets(buf, sizeof(buf), f);
2002 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2004 if (ast_all_zeros(buf))
2006 if ((ret = ast_el_add_history(buf)) == -1)
2014 static void ast_remotecontrol(char * data)
2018 char filename[80] = "";
2024 char *stringp = NULL;
2029 read(ast_consock, buf, sizeof(buf));
2031 write(ast_consock, data, strlen(data) + 1);
2033 hostname = strsep(&stringp, "/");
2034 cpid = strsep(&stringp, "/");
2035 version = strsep(&stringp, "\n");
2037 version = "<Version Unknown>";
2039 strsep(&stringp, ".");
2044 snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
2045 fdprint(ast_consock, tmp);
2046 snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
2047 fdprint(ast_consock, tmp);
2049 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2050 fdprint(ast_consock, tmp);
2052 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2053 remotehostname = hostname;
2055 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2056 if (el_hist == NULL || el == NULL)
2057 ast_el_initialize();
2059 el_set(el, EL_GETCFN, ast_el_read_char);
2061 if (!ast_strlen_zero(filename))
2062 ast_el_read_history(filename);
2064 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2067 fds.fd = ast_consock;
2068 fds.events = POLLIN;
2070 while (poll(&fds, 1, 100) > 0)
2071 ast_el_read_char(el, &tempchar);
2075 ebuf = (char *)el_gets(el, &num);
2077 if (!ast_strlen_zero(ebuf)) {
2078 if (ebuf[strlen(ebuf)-1] == '\n')
2079 ebuf[strlen(ebuf)-1] = '\0';
2080 if (!remoteconsolehandler(ebuf)) {
2081 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2083 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2089 printf("\nDisconnected from Asterisk server\n");
2092 static int show_version(void)
2094 printf("Asterisk " ASTERISK_VERSION "\n");
2098 static int show_cli_help(void) {
2099 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2100 printf("Usage: asterisk [OPTIONS]\n");
2101 printf("Valid Options:\n");
2102 printf(" -V Display version number and exit\n");
2103 printf(" -C <configfile> Use an alternate configuration file\n");
2104 printf(" -G <group> Run as a group other than the caller\n");
2105 printf(" -U <user> Run as a user other than the caller\n");
2106 printf(" -c Provide console CLI\n");
2107 printf(" -d Enable extra debugging\n");
2108 #if HAVE_WORKING_FORK
2109 printf(" -f Do not fork\n");
2110 printf(" -F Always fork\n");
2112 printf(" -g Dump core in case of a crash\n");
2113 printf(" -h This help screen\n");
2114 printf(" -i Initialize crypto keys at startup\n");
2115 printf(" -I Enable internal timing if Zaptel timer is available\n");
2116 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2117 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2118 printf(" -m Mute the console from debugging and verbose output\n");
2119 printf(" -n Disable console colorization\n");
2120 printf(" -p Run as pseudo-realtime thread\n");
2121 printf(" -q Quiet mode (suppress output)\n");
2122 printf(" -r Connect to Asterisk on this machine\n");
2123 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2124 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2125 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2126 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2127 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2132 static void ast_readconfig(void)
2134 struct ast_config *cfg;
2135 struct ast_variable *v;
2136 char *config = AST_CONFIG_FILE;
2138 if (ast_opt_override_config) {
2139 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2141 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2143 cfg = ast_config_load(config);
2146 /* init with buildtime config */
2147 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2148 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2149 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2150 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2151 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2152 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2153 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2154 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2155 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2156 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2157 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2158 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2159 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2161 /* no asterisk.conf? no problem, use buildtime config! */
2166 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2167 if (!strcasecmp(v->name, "astctlpermissions")) {
2168 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2169 } else if (!strcasecmp(v->name, "astctlowner")) {
2170 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2171 } else if (!strcasecmp(v->name, "astctlgroup")) {
2172 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2173 } else if (!strcasecmp(v->name, "astctl")) {
2174 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2178 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2179 if (!strcasecmp(v->name, "astetcdir")) {
2180 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2181 } else if (!strcasecmp(v->name, "astspooldir")) {
2182 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2183 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2184 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2185 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2186 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2187 } else if (!strcasecmp(v->name, "astdatadir")) {
2188 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2189 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2190 } else if (!strcasecmp(v->name, "astlogdir")) {
2191 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2192 } else if (!strcasecmp(v->name, "astagidir")) {
2193 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2194 } else if (!strcasecmp(v->name, "astrundir")) {
2195 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2196 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2197 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2198 } else if (!strcasecmp(v->name, "astmoddir")) {
2199 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2203 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2204 /* verbose level (-v at startup) */
2205 if (!strcasecmp(v->name, "verbose")) {
2206 option_verbose = atoi(v->value);
2207 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2208 } else if (!strcasecmp(v->name, "timestamp")) {
2209 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2210 /* whether or not to support #exec in config files */
2211 } else if (!strcasecmp(v->name, "execincludes")) {
2212 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2213 /* debug level (-d at startup) */
2214 } else if (!strcasecmp(v->name, "debug")) {
2216 if (sscanf(v->value, "%d", &option_debug) != 1) {
2217 option_debug = ast_true(v->value);
2219 #if HAVE_WORKING_FORK
2220 /* Disable forking (-f at startup) */
2221 } else if (!strcasecmp(v->name, "nofork")) {
2222 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2223 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2224 } else if (!strcasecmp(v->name, "alwaysfork")) {
2225 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2227 /* Run quietly (-q at startup ) */
2228 } else if (!strcasecmp(v->name, "quiet")) {
2229 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2230 /* Run as console (-c at startup, implies nofork) */
2231 } else if (!strcasecmp(v->name, "console")) {
2232 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2233 /* Run with high priority if the O/S permits (-p at startup) */
2234 } else if (!strcasecmp(v->name, "highpriority")) {
2235 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2236 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2237 } else if (!strcasecmp(v->name, "initcrypto")) {
2238 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2239 /* Disable ANSI colors for console (-c at startup) */
2240 } else if (!strcasecmp(v->name, "nocolor")) {
2241 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2242 /* Disable some usage warnings for picky people :p */
2243 } else if (!strcasecmp(v->name, "dontwarn")) {
2244 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2245 /* Dump core in case of crash (-g) */
2246 } else if (!strcasecmp(v->name, "dumpcore")) {
2247 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2248 /* Cache recorded sound files to another directory during recording */
2249 } else if (!strcasecmp(v->name, "cache_record_files")) {
2250 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2251 /* Specify cache directory */
2252 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2253 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2254 /* Build transcode paths via SLINEAR, instead of directly */
2255 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2256 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2257 /* Transmit SLINEAR silence while a channel is being recorded */
2258 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2259 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2260 /* Enable internal timing */
2261 } else if (!strcasecmp(v->name, "internal_timing")) {
2262 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2263 } else if (!strcasecmp(v->name, "maxcalls")) {
2264 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2265 option_maxcalls = 0;
2267 } else if (!strcasecmp(v->name, "maxload")) {
2270 if (getloadavg(test, 1) == -1) {
2271 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2272 option_maxload = 0.0;
2273 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2274 option_maxload = 0.0;
2276 /* What user to run as */
2277 } else if (!strcasecmp(v->name, "runuser")) {
2278 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2279 /* What group to run as */
2280 } else if (!strcasecmp(v->name, "rungroup")) {
2281 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2282 } else if (!strcasecmp(v->name, "systemname")) {
2283 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2284 } else if (!strcasecmp(v->name, "languageprefix")) {
2285 ast_language_is_prefix = ast_true(v->value);
2288 ast_config_destroy(cfg);
2291 int main(int argc, char *argv[])
2294 char filename[80] = "";
2295 char hostname[MAXHOSTNAMELEN] = "";
2302 int is_child_of_nonroot = 0;
2304 char *runuser = NULL, *rungroup = NULL;
2306 /* Remember original args for restart */
2307 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2308 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2309 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2311 for (x=0; x<argc; x++)
2315 /* if the progname is rasterisk consider it a remote console */
2316 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2317 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2319 if (gethostname(hostname, sizeof(hostname)-1))
2320 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2321 ast_mainpid = getpid();
2325 ast_builtins_init();
2328 /* When Asterisk restarts after it has dropped the root privileges,
2329 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2331 if (getenv("ASTERISK_ALREADY_NONROOT"))
2332 is_child_of_nonroot=1;
2334 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2335 /* Check for options */
2336 while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2338 #if HAVE_WORKING_FORK
2340 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2343 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2348 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2351 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2354 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2357 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2360 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2363 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2367 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2370 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2373 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2374 option_maxcalls = 0;
2377 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2378 option_maxload = 0.0;
2381 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2384 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2387 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2390 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2394 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2395 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2398 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2401 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2404 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2423 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2424 ast_register_verbose(console_verboser);
2428 if (ast_opt_console && !option_verbose)
2429 ast_verbose("[ Booting...\n");
2431 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2432 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2433 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2436 /* For remote connections, change the name of the remote connection.
2437 * We do this for the benefit of init scripts (which need to know if/when
2438 * the main asterisk process has died yet). */
2439 if (ast_opt_remote) {
2440 strcpy(argv[0], "rasterisk");
2441 for (x = 1; x < argc; x++) {
2442 argv[x] = argv[0] + 10;
2446 if (ast_opt_console && !option_verbose)
2447 ast_verbose("[ Reading Master Configuration ]\n");
2450 if (ast_opt_dump_core) {
2452 memset(&l, 0, sizeof(l));
2453 l.rlim_cur = RLIM_INFINITY;
2454 l.rlim_max = RLIM_INFINITY;
2455 if (setrlimit(RLIMIT_CORE, &l)) {
2456 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2460 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2461 rungroup = ast_config_AST_RUN_GROUP;
2462 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2463 runuser = ast_config_AST_RUN_USER;
2467 if (!is_child_of_nonroot)
2468 ast_set_priority(ast_opt_high_priority);
2470 if (!is_child_of_nonroot && rungroup) {
2472 gr = getgrnam(rungroup);
2474 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2477 if (setgid(gr->gr_gid)) {
2478 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2481 if (setgroups(0, NULL)) {
2482 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2486 ast_verbose("Running as group '%s'\n", rungroup);
2489 if (!is_child_of_nonroot && runuser) {
2491 pw = getpwnam(runuser);
2493 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2497 if (setgid(pw->pw_gid)) {
2498 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2501 if (initgroups(pw->pw_name, pw->pw_gid)) {
2502 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2506 if (setuid(pw->pw_uid)) {
2507 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2510 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2512 ast_verbose("Running as user '%s'\n", runuser);
2515 #endif /* __CYGWIN__ */
2518 if (geteuid() && ast_opt_dump_core) {
2519 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2520 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2529 if (ast_opt_console && !option_verbose)
2530 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2531 /* custom config setup */
2532 register_config_cli();
2535 if (ast_opt_console) {
2536 if (el_hist == NULL || el == NULL)
2537 ast_el_initialize();
2539 if (!ast_strlen_zero(filename))
2540 ast_el_read_history(filename);
2543 if (ast_tryconnect()) {
2544 /* One is already running */
2545 if (ast_opt_remote) {
2547 ast_remotecontrol(xarg);
2548 quit_handler(0, 0, 0, 0);
2551 printf(term_quit());
2552 ast_remotecontrol(NULL);
2553 quit_handler(0, 0, 0, 0);
2556 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2557 printf(term_quit());
2560 } else if (ast_opt_remote || ast_opt_exec) {
2561 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2562 printf(term_quit());
2565 /* Blindly write pid file since we couldn't connect */
2566 unlink(ast_config_AST_PID);
2567 f = fopen(ast_config_AST_PID, "w");
2569 fprintf(f, "%ld\n", (long)getpid());
2572 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2574 #if HAVE_WORKING_FORK
2575 if (ast_opt_always_fork || !ast_opt_no_fork) {
2577 ast_mainpid = getpid();
2578 /* Blindly re-write pid file since we are forking */
2579 unlink(ast_config_AST_PID);
2580 f = fopen(ast_config_AST_PID, "w");
2582 fprintf(f, "%ld\n", (long)ast_mainpid);
2585 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2589 /* Test recursive mutex locking. */
2590 if (test_for_thread_safety())
2591 ast_verbose("Warning! Asterisk is not thread safe.\n");
2595 sigaddset(&sigs, SIGHUP);
2596 sigaddset(&sigs, SIGTERM);
2597 sigaddset(&sigs, SIGINT);
2598 sigaddset(&sigs, SIGPIPE);
2599 sigaddset(&sigs, SIGWINCH);
2600 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2601 signal(SIGURG, urg_handler);
2602 signal(SIGINT, __quit_handler);
2603 signal(SIGTERM, __quit_handler);
2604 signal(SIGHUP, hup_handler);
2605 signal(SIGCHLD, child_handler);
2606 signal(SIGPIPE, SIG_IGN);
2608 /* ensure that the random number generators are seeded with a different value every time
2611 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2612 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2614 if (init_logger()) {
2615 printf(term_quit());
2618 if (load_modules(1)) {
2619 printf(term_quit());
2623 if (dnsmgr_init()) {
2624 printf(term_quit());
2630 ast_channels_init();
2632 if (init_manager()) {
2633 printf(term_quit());
2637 if (ast_cdr_engine_init()) {
2638 printf(term_quit());
2642 if (ast_device_state_engine_init()) {
2643 printf(term_quit());
2651 if (ast_image_init()) {
2652 printf(term_quit());
2656 if (ast_file_init()) {
2657 printf(term_quit());
2662 printf(term_quit());
2666 if (init_framer()) {
2667 printf(term_quit());
2672 printf(term_quit());
2676 if (ast_enum_init()) {
2677 printf(term_quit());
2681 if (load_modules(0)) {
2682 printf(term_quit());
2686 dnsmgr_start_refresh();
2688 /* We might have the option of showing a console, but for now just
2690 if (ast_opt_console && !option_verbose)
2691 ast_verbose(" ]\n");
2692 if (option_verbose || ast_opt_console)
2693 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2694 if (ast_opt_no_fork)
2695 consolethread = pthread_self();
2697 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2698 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2700 #ifdef __AST_DEBUG_MALLOC
2704 time(&ast_startuptime);
2705 ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2707 if (ast_opt_console) {
2708 /* Console stuff now... */
2709 /* Register our quit function */
2711 set_icon("Asterisk");
2712 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2716 buf = (char *)el_gets(el, &num);
2718 if (buf[strlen(buf)-1] == '\n')
2719 buf[strlen(buf)-1] = '\0';
2721 consolehandler((char *)buf);
2723 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2724 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2725 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2727 fd = open("/dev/null", O_RDWR);
2729 dup2(fd, STDOUT_FILENO);
2730 dup2(fd, STDIN_FILENO);
2732 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2740 for (;;) { /* apparently needed for Mac OS X */
2741 struct pollfd p = { -1 /* no descriptor */, 0, 0 };