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 ast_replace_sigchld();
655 if (ast_opt_high_priority)
657 /* Close file descriptors and launch system command */
658 for (x = STDERR_FILENO + 1; x < 4096; x++)
660 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
662 } else if (pid > 0) {
664 res = wait4(pid, &status, 0, &rusage);
666 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
668 } else if (errno != EINTR)
672 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
676 ast_unreplace_sigchld();
682 * \brief mute or unmute a console from logging
684 void ast_console_toggle_mute(int fd) {
686 for (x = 0;x < AST_MAX_CONNECTS; x++) {
687 if (fd == consoles[x].fd) {
688 if (consoles[x].mute) {
689 consoles[x].mute = 0;
690 ast_cli(fd, "Console is not muted anymore.\n");
692 consoles[x].mute = 1;
693 ast_cli(fd, "Console is muted.\n");
698 ast_cli(fd, "Couldn't find remote console.\n");
702 * \brief log the string to all attached console clients
704 static void ast_network_puts_mutable(const char *string)
707 for (x = 0;x < AST_MAX_CONNECTS; x++) {
708 if (consoles[x].mute)
710 if (consoles[x].fd > -1)
711 fdprint(consoles[x].p[1], string);
716 * \brief log the string to the console, and all attached
719 void ast_console_puts_mutable(const char *string)
721 fputs(string, stdout);
723 ast_network_puts_mutable(string);
727 * \brief write the string to all attached console clients
729 static void ast_network_puts(const char *string)
732 for (x=0; x < AST_MAX_CONNECTS; x++) {
733 if (consoles[x].fd > -1)
734 fdprint(consoles[x].p[1], string);
739 * write the string to the console, and all attached
742 void ast_console_puts(const char *string)
744 fputs(string, stdout);
746 ast_network_puts(string);
749 static void network_verboser(const char *s, int pos, int replace, int complete)
754 if ((t = alloca(strlen(s) + 2))) {
755 sprintf(t, "\r%s", s);
757 ast_network_puts_mutable(t);
759 ast_log(LOG_ERROR, "Out of memory\n");
760 ast_network_puts_mutable(s);
764 ast_network_puts_mutable(s);
768 static pthread_t lthread;
770 static void *netconsole(void *vconsole)
772 struct console *con = vconsole;
773 char hostname[MAXHOSTNAMELEN] = "";
776 struct pollfd fds[2];
778 if (gethostname(hostname, sizeof(hostname)-1))
779 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
780 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
781 fdprint(con->fd, tmp);
784 fds[0].events = POLLIN;
786 fds[1].fd = con->p[0];
787 fds[1].events = POLLIN;
790 res = poll(fds, 2, -1);
793 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
796 if (fds[0].revents) {
797 res = read(con->fd, tmp, sizeof(tmp));
802 ast_cli_command(con->fd, tmp);
804 if (fds[1].revents) {
805 res = read(con->p[0], tmp, sizeof(tmp));
807 ast_log(LOG_ERROR, "read returned %d\n", res);
810 res = write(con->fd, tmp, res);
815 if (option_verbose > 2)
816 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
825 static void *listener(void *unused)
827 struct sockaddr_un sunaddr;
832 struct pollfd fds[1];
834 pthread_attr_init(&attr);
835 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
839 fds[0].fd = ast_socket;
840 fds[0].events = POLLIN;
841 s = poll(fds, 1, -1);
844 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
847 len = sizeof(sunaddr);
848 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
851 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
853 for (x = 0; x < AST_MAX_CONNECTS; x++) {
854 if (consoles[x].fd < 0) {
855 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
856 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
858 fdprint(s, "Server failed to create pipe\n");
862 flags = fcntl(consoles[x].p[1], F_GETFL);
863 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
865 consoles[x].mute = ast_opt_mute;
866 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
867 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
868 close(consoles[x].p[0]);
869 close(consoles[x].p[1]);
871 fdprint(s, "Server failed to spawn thread\n");
877 if (x >= AST_MAX_CONNECTS) {
878 fdprint(s, "No more connections allowed\n");
879 ast_log(LOG_WARNING, "No more connections allowed\n");
881 } else if (consoles[x].fd > -1) {
882 if (option_verbose > 2)
883 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
890 static int ast_makesocket(void)
892 struct sockaddr_un sunaddr;
898 for (x = 0; x < AST_MAX_CONNECTS; x++)
900 unlink(ast_config_AST_SOCKET);
901 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
902 if (ast_socket < 0) {
903 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
906 memset(&sunaddr, 0, sizeof(sunaddr));
907 sunaddr.sun_family = AF_LOCAL;
908 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
909 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
911 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
916 res = listen(ast_socket, 2);
918 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
923 ast_register_verbose(network_verboser);
924 ast_pthread_create(<hread, NULL, listener, NULL);
926 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
928 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
929 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
935 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
937 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
938 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
944 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
945 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
947 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
950 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
952 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
953 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
959 static int ast_tryconnect(void)
961 struct sockaddr_un sunaddr;
963 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
964 if (ast_consock < 0) {
965 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
968 memset(&sunaddr, 0, sizeof(sunaddr));
969 sunaddr.sun_family = AF_LOCAL;
970 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
971 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
980 /*! \brief Urgent handler
982 Called by soft_hangup to interrupt the poll, read, or other
983 system call. We don't actually need to do anything though.
984 Remember: Cannot EVER ast_log from within a signal handler
985 SLD: seems to be some pthread activity relating to the printf anyway:
986 which is leading to a deadlock?
988 static void urg_handler(int num)
991 if (option_debug > 2)
992 printf("-- Asterisk Urgent handler\n");
994 signal(num, urg_handler);
998 static void hup_handler(int num)
1000 if (option_verbose > 1)
1001 printf("Received HUP signal -- Reloading configs\n");
1003 execvp(_argv[0], _argv);
1004 /* XXX This could deadlock XXX */
1005 ast_module_reload(NULL);
1006 signal(num, hup_handler);
1009 static void child_handler(int sig)
1011 /* Must not ever ast_log or ast_verbose within signal handler */
1015 * Reap all dead children -- not just one
1017 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1019 if (n == 0 && option_debug)
1020 printf("Huh? Child handler, but nobody there?\n");
1021 signal(sig, child_handler);
1024 /*! \brief Set an X-term or screen title */
1025 static void set_title(char *text)
1027 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1028 fprintf(stdout, "\033]2;%s\007", text);
1031 static void set_icon(char *text)
1033 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1034 fprintf(stdout, "\033]1;%s\007", text);
1037 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1038 else. If your PBX has heavy activity on it, this is a good thing. */
1039 int ast_set_priority(int pri)
1041 struct sched_param sched;
1042 memset(&sched, 0, sizeof(sched));
1045 sched.sched_priority = 10;
1046 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1047 ast_log(LOG_WARNING, "Unable to set high priority\n");
1051 ast_verbose("Set to realtime thread\n");
1053 sched.sched_priority = 0;
1054 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
1055 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1061 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1062 ast_log(LOG_WARNING, "Unable to set high priority\n");
1066 ast_verbose("Set to high priority\n");
1068 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1069 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1077 static void ast_run_atexits(void)
1079 struct ast_atexit *ae;
1080 AST_LIST_LOCK(&atexits);
1081 AST_LIST_TRAVERSE(&atexits, ae, list) {
1085 AST_LIST_UNLOCK(&atexits);
1088 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1090 char filename[80] = "";
1093 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1094 ast_cdr_engine_term();
1098 /* Begin shutdown routine, hanging up active channels */
1099 ast_begin_shutdown(1);
1100 if (option_verbose && ast_opt_console)
1101 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1105 /* Wait up to 15 seconds for all channels to go away */
1108 if (!ast_active_channels())
1112 /* Sleep 1/10 of a second */
1117 ast_begin_shutdown(0);
1118 if (option_verbose && ast_opt_console)
1119 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1121 if (!ast_active_channels())
1129 if (!shuttingdown) {
1130 if (option_verbose && ast_opt_console)
1131 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1135 if (ast_opt_console || ast_opt_remote) {
1137 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1138 if (!ast_strlen_zero(filename))
1139 ast_el_write_history(filename);
1142 if (el_hist != NULL)
1143 history_end(el_hist);
1146 ast_verbose("Executing last minute cleanups\n");
1148 /* Called on exit */
1149 if (option_verbose && ast_opt_console)
1150 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1151 else if (option_debug)
1152 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1153 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1154 if (ast_socket > -1) {
1157 unlink(ast_config_AST_SOCKET);
1158 pthread_cancel(lthread);
1160 if (ast_consock > -1)
1162 if (!ast_opt_remote)
1163 unlink(ast_config_AST_PID);
1164 printf(term_quit());
1166 if (option_verbose || ast_opt_console)
1167 ast_verbose("Preparing for Asterisk restart...\n");
1168 /* Mark all FD's for closing on exec */
1169 for (x=3; x < 32768; x++) {
1170 fcntl(x, F_SETFD, FD_CLOEXEC);
1172 if (option_verbose || ast_opt_console)
1173 ast_verbose("Restarting Asterisk NOW...\n");
1179 /* If there is a consolethread running send it a SIGHUP
1180 so it can execvp, otherwise we can do it ourselves */
1181 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1182 pthread_kill(consolethread, SIGHUP);
1183 /* Give the signal handler some time to complete */
1186 execvp(_argv[0], _argv);
1195 static void __quit_handler(int num)
1197 quit_handler(num, 0, 1, 0);
1200 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1203 if (!strncmp(s, cmp, strlen(cmp))) {
1204 c = s + strlen(cmp);
1205 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1211 static void console_verboser(const char *s, int pos, int replace, int complete)
1214 const char *c = NULL;
1215 /* Return to the beginning of the line */
1217 fprintf(stdout, "\r");
1218 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1219 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1220 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1221 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
1225 fputs(c + pos,stdout);
1227 fputs(s + pos,stdout);
1230 /* Wake up a poll()ing console */
1231 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1232 pthread_kill(consolethread, SIGURG);
1236 static int ast_all_zeros(char *s)
1246 static void consolehandler(char *s)
1250 /* Called when readline data is available */
1251 if (s && !ast_all_zeros(s))
1252 ast_el_add_history(s);
1253 /* Give the console access to the shell */
1255 /* The real handler for bang */
1258 ast_safe_system(s+1);
1260 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1262 ast_cli_command(STDOUT_FILENO, s);
1264 fprintf(stdout, "\nUse \"quit\" to exit\n");
1267 static int remoteconsolehandler(char *s)
1270 /* Called when readline data is available */
1271 if (s && !ast_all_zeros(s))
1272 ast_el_add_history(s);
1273 /* Give the console access to the shell */
1275 /* The real handler for bang */
1278 ast_safe_system(s+1);
1280 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1283 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1284 (s[4] == '\0' || isspace(s[4]))) {
1285 quit_handler(0, 0, 0, 0);
1289 fprintf(stdout, "\nUse \"quit\" to exit\n");
1294 static char abort_halt_help[] =
1295 "Usage: abort shutdown\n"
1296 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1297 " call operations.\n";
1299 static char shutdown_now_help[] =
1301 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1303 static char shutdown_gracefully_help[] =
1304 "Usage: stop gracefully\n"
1305 " Causes Asterisk to not accept new calls, and exit when all\n"
1306 " active calls have terminated normally.\n";
1308 static char shutdown_when_convenient_help[] =
1309 "Usage: stop when convenient\n"
1310 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1312 static char restart_now_help[] =
1313 "Usage: restart now\n"
1314 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1317 static char restart_gracefully_help[] =
1318 "Usage: restart gracefully\n"
1319 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1320 " restart when all active calls have ended.\n";
1322 static char restart_when_convenient_help[] =
1323 "Usage: restart when convenient\n"
1324 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1326 static char bang_help[] =
1327 "Usage: !<command>\n"
1328 " Executes a given shell command\n";
1330 static char show_warranty_help[] =
1331 "Usage: show warranty\n"
1332 " Shows the warranty (if any) for this copy of Asterisk.\n";
1334 static char show_license_help[] =
1335 "Usage: show license\n"
1336 " Shows the license(s) for this copy of Asterisk.\n";
1338 static char version_help[] =
1339 "Usage: show version\n"
1340 " Shows Asterisk version information.\n";
1342 static int handle_version(int fd, int argc, char *argv[])
1345 return RESULT_SHOWUSAGE;
1346 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1347 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1348 ast_build_machine, ast_build_os, ast_build_date);
1349 return RESULT_SUCCESS;
1353 static int handle_quit(int fd, int argc, char *argv[])
1356 return RESULT_SHOWUSAGE;
1357 quit_handler(0, 0, 1, 0);
1358 return RESULT_SUCCESS;
1362 static int handle_shutdown_now(int fd, int argc, char *argv[])
1365 return RESULT_SHOWUSAGE;
1366 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1367 return RESULT_SUCCESS;
1370 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1373 return RESULT_SHOWUSAGE;
1374 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1375 return RESULT_SUCCESS;
1378 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1381 return RESULT_SHOWUSAGE;
1382 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1383 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1384 return RESULT_SUCCESS;
1387 static int handle_restart_now(int fd, int argc, char *argv[])
1390 return RESULT_SHOWUSAGE;
1391 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1392 return RESULT_SUCCESS;
1395 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1398 return RESULT_SHOWUSAGE;
1399 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1400 return RESULT_SUCCESS;
1403 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1406 return RESULT_SHOWUSAGE;
1407 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1408 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1409 return RESULT_SUCCESS;
1412 static int handle_abort_halt(int fd, int argc, char *argv[])
1415 return RESULT_SHOWUSAGE;
1416 ast_cancel_shutdown();
1418 return RESULT_SUCCESS;
1421 static int handle_bang(int fd, int argc, char *argv[])
1423 return RESULT_SUCCESS;
1425 static const char *warranty_lines[] = {
1429 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1430 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1431 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1432 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1433 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1434 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1435 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1436 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1437 "REPAIR OR CORRECTION.\n",
1439 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1440 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1441 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1442 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1443 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1444 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1445 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1446 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1447 "POSSIBILITY OF SUCH DAMAGES.\n",
1450 static int show_warranty(int fd, int argc, char *argv[])
1454 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1455 ast_cli(fd, (char *) warranty_lines[x]);
1457 return RESULT_SUCCESS;
1460 static const char *license_lines[] = {
1462 "This program is free software; you can redistribute it and/or modify\n",
1463 "it under the terms of the GNU General Public License version 2 as\n",
1464 "published by the Free Software Foundation.\n",
1466 "This program also contains components licensed under other licenses.\n",
1469 "This program is distributed in the hope that it will be useful,\n",
1470 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1471 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1472 "GNU General Public License for more details.\n",
1474 "You should have received a copy of the GNU General Public License\n",
1475 "along with this program; if not, write to the Free Software\n",
1476 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1479 static int show_license(int fd, int argc, char *argv[])
1483 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1484 ast_cli(fd, (char *) license_lines[x]);
1486 return RESULT_SUCCESS;
1489 #define ASTERISK_PROMPT "*CLI> "
1491 #define ASTERISK_PROMPT2 "%s*CLI> "
1493 static struct ast_cli_entry core_cli[] = {
1494 { { "abort", "halt", NULL }, handle_abort_halt,
1495 "Cancel a running halt", abort_halt_help },
1496 { { "stop", "now", NULL }, handle_shutdown_now,
1497 "Shut down Asterisk immediately", shutdown_now_help },
1498 { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1499 "Gracefully shut down Asterisk", shutdown_gracefully_help },
1500 { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1501 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1502 { { "restart", "now", NULL }, handle_restart_now,
1503 "Restart Asterisk immediately", restart_now_help },
1504 { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1505 "Restart Asterisk gracefully", restart_gracefully_help },
1506 { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1507 "Restart Asterisk at empty call volume", restart_when_convenient_help },
1508 { { "show", "warranty", NULL }, show_warranty,
1509 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
1510 { { "show", "license", NULL }, show_license,
1511 "Show the license(s) for this copy of Asterisk", show_license_help },
1512 { { "show", "version", NULL }, handle_version,
1513 "Display version info", version_help },
1514 { { "!", NULL }, handle_bang,
1515 "Execute a shell command", bang_help },
1516 #if !defined(LOW_MEMORY)
1517 { { "show", "version", "files", NULL }, handle_show_version_files,
1518 "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1519 { { "show", "threads", NULL }, handle_show_threads,
1520 "Show running threads", show_threads_help, NULL },
1521 { { "show", "profile", NULL }, handle_show_profile,
1522 "Show profiling info"},
1523 { { "clear", "profile", NULL }, handle_show_profile,
1524 "Clear profiling info"},
1525 #endif /* ! LOW_MEMORY */
1528 static int ast_el_read_char(EditLine *el, char *cp)
1532 struct pollfd fds[2];
1539 fds[0].fd = ast_consock;
1540 fds[0].events = POLLIN;
1541 if (!ast_opt_exec) {
1542 fds[1].fd = STDIN_FILENO;
1543 fds[1].events = POLLIN;
1546 res = poll(fds, max, -1);
1550 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1554 if (!ast_opt_exec && fds[1].revents) {
1555 num_read = read(STDIN_FILENO, cp, 1);
1561 if (fds[0].revents) {
1562 res = read(ast_consock, buf, sizeof(buf) - 1);
1563 /* if the remote side disappears exit */
1565 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1566 if (!ast_opt_reconnect) {
1567 quit_handler(0, 0, 0, 0);
1570 int reconnects_per_second = 20;
1571 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1572 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1573 if (ast_tryconnect()) {
1574 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1575 printf(term_quit());
1579 usleep(1000000 / reconnects_per_second);
1582 if (tries >= 30 * reconnects_per_second) {
1583 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1584 quit_handler(0, 0, 0, 0);
1591 if (!ast_opt_exec && !lastpos)
1592 write(STDOUT_FILENO, "\r", 1);
1593 write(STDOUT_FILENO, buf, res);
1594 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1607 static char *cli_prompt(EditLine *el)
1609 static char prompt[200];
1614 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1615 char *t = pfmt, *p = prompt;
1616 memset(prompt, 0, sizeof(prompt));
1617 while (*t != '\0' && *p < sizeof(prompt)) {
1619 char hostname[MAXHOSTNAMELEN]="";
1626 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1630 case 'C': /* color */
1632 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1633 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1635 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1636 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1640 /* If the color has been reset correctly, then there's no need to reset it later */
1641 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1647 case 'd': /* date */
1648 memset(&tm, 0, sizeof(tm));
1650 if (localtime_r(&ts, &tm)) {
1651 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1654 case 'h': /* hostname */
1655 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1656 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1658 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1661 case 'H': /* short hostname */
1662 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1663 for (i = 0; i < sizeof(hostname); i++) {
1664 if (hostname[i] == '.') {
1669 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1671 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1675 case 'l': /* load avg */
1677 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1678 float avg1, avg2, avg3;
1679 int actproc, totproc, npid, which;
1680 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1681 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1682 if (sscanf(t, "%d", &which) == 1) {
1685 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1688 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1691 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1694 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1697 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1704 case 's': /* Asterisk system name (from asterisk.conf) */
1705 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1707 case 't': /* time */
1708 memset(&tm, 0, sizeof(tm));
1710 if (localtime_r(&ts, &tm)) {
1711 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1714 case '#': /* process console or remote? */
1715 if (!ast_opt_remote) {
1716 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1718 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1721 case '%': /* literal % */
1722 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1724 case '\0': /* % is last character - prevent bug */
1728 while (*p != '\0') {
1739 /* Force colors back to normal at end */
1740 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1741 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1742 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1744 strncat(p, term_code, sizeof(term_code));
1747 } else if (remotehostname)
1748 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1750 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1755 static char **ast_el_strtoarr(char *buf)
1757 char **match_list = NULL, *retstr;
1758 size_t match_list_len;
1762 while ( (retstr = strsep(&buf, " ")) != NULL) {
1764 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1766 if (matches + 1 >= match_list_len) {
1767 match_list_len <<= 1;
1768 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1769 /* TODO: Handle memory allocation failure */
1773 match_list[matches++] = strdup(retstr);
1777 return (char **) NULL;
1779 if (matches >= match_list_len) {
1780 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1781 /* TODO: Handle memory allocation failure */
1785 match_list[matches] = (char *) NULL;
1790 static int ast_el_sort_compare(const void *i1, const void *i2)
1794 s1 = ((char **)i1)[0];
1795 s2 = ((char **)i2)[0];
1797 return strcasecmp(s1, s2);
1800 static int ast_cli_display_match_list(char **matches, int len, int max)
1802 int i, idx, limit, count;
1803 int screenwidth = 0;
1804 int numoutput = 0, numoutputline = 0;
1806 screenwidth = ast_get_termcols(STDOUT_FILENO);
1808 /* find out how many entries can be put on one line, with two spaces between strings */
1809 limit = screenwidth / (max + 2);
1813 /* how many lines of output */
1814 count = len / limit;
1815 if (count * limit < len)
1820 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1822 for (; count > 0; count--) {
1824 for (i=0; i < limit && matches[idx]; i++, idx++) {
1826 /* Don't print dupes */
1827 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1830 matches[idx] = NULL;
1836 fprintf(stdout, "%-*s ", max, matches[idx]);
1838 matches[idx] = NULL;
1840 if (numoutputline > 0)
1841 fprintf(stdout, "\n");
1848 static char *cli_complete(EditLine *el, int ch)
1854 int retval = CC_ERROR;
1858 LineInfo *lf = (LineInfo *)el_line(el);
1860 *(char *)lf->cursor = '\0';
1861 ptr = (char *)lf->cursor;
1863 while (ptr > lf->buffer) {
1864 if (isspace(*ptr)) {
1872 len = lf->cursor - ptr;
1874 if (ast_opt_remote) {
1875 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1876 fdprint(ast_consock, buf);
1877 res = read(ast_consock, buf, sizeof(buf));
1879 nummatches = atoi(buf);
1881 if (nummatches > 0) {
1883 int mlen = 0, maxmbuf = 2048;
1884 /* Start with a 2048 byte buffer */
1885 if (!(mbuf = ast_malloc(maxmbuf)))
1886 return (char *)(CC_ERROR);
1887 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1888 fdprint(ast_consock, buf);
1891 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1892 if (mlen + 1024 > maxmbuf) {
1893 /* Every step increment buffer 1024 bytes */
1895 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1896 return (char *)(CC_ERROR);
1898 /* Only read 1024 bytes at a time */
1899 res = read(ast_consock, mbuf + mlen, 1024);
1905 matches = ast_el_strtoarr(mbuf);
1908 matches = (char **) NULL;
1910 char **p, *oldbuf=NULL;
1912 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1913 for (p = matches; p && *p; p++) {
1914 if (!oldbuf || strcmp(*p,oldbuf))
1922 int matches_num, maxlen, match_len;
1924 if (matches[0][0] != '\0') {
1925 el_deletestr(el, (int) len);
1926 el_insertstr(el, matches[0]);
1927 retval = CC_REFRESH;
1930 if (nummatches == 1) {
1931 /* Found an exact match */
1932 el_insertstr(el, " ");
1933 retval = CC_REFRESH;
1935 /* Must be more than one match */
1936 for (i=1, maxlen=0; matches[i]; i++) {
1937 match_len = strlen(matches[i]);
1938 if (match_len > maxlen)
1941 matches_num = i - 1;
1942 if (matches_num >1) {
1943 fprintf(stdout, "\n");
1944 ast_cli_display_match_list(matches, nummatches, maxlen);
1945 retval = CC_REDISPLAY;
1947 el_insertstr(el," ");
1948 retval = CC_REFRESH;
1954 return (char *)(long)retval;
1957 static int ast_el_initialize(void)
1960 char *editor = getenv("AST_EDITOR");
1964 if (el_hist != NULL)
1965 history_end(el_hist);
1967 el = el_init("asterisk", stdin, stdout, stderr);
1968 el_set(el, EL_PROMPT, cli_prompt);
1970 el_set(el, EL_EDITMODE, 1);
1971 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1972 el_hist = history_init();
1973 if (!el || !el_hist)
1976 /* setup history with 100 entries */
1977 history(el_hist, &ev, H_SETSIZE, 100);
1979 el_set(el, EL_HIST, history, el_hist);
1981 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1982 /* Bind <tab> to command completion */
1983 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1984 /* Bind ? to command completion */
1985 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1986 /* Bind ^D to redisplay */
1987 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1992 static int ast_el_add_history(char *buf)
1996 if (el_hist == NULL || el == NULL)
1997 ast_el_initialize();
1998 if (strlen(buf) > 256)
2000 return (history(el_hist, &ev, H_ENTER, buf));
2003 static int ast_el_write_history(char *filename)
2007 if (el_hist == NULL || el == NULL)
2008 ast_el_initialize();
2010 return (history(el_hist, &ev, H_SAVE, filename));
2013 static int ast_el_read_history(char *filename)
2019 if (el_hist == NULL || el == NULL)
2020 ast_el_initialize();
2022 if ((f = fopen(filename, "r")) == NULL)
2026 fgets(buf, sizeof(buf), f);
2027 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2029 if (ast_all_zeros(buf))
2031 if ((ret = ast_el_add_history(buf)) == -1)
2039 static void ast_remotecontrol(char * data)
2043 char filename[80] = "";
2049 char *stringp = NULL;
2054 read(ast_consock, buf, sizeof(buf));
2056 write(ast_consock, data, strlen(data) + 1);
2058 hostname = strsep(&stringp, "/");
2059 cpid = strsep(&stringp, "/");
2060 version = strsep(&stringp, "\n");
2062 version = "<Version Unknown>";
2064 strsep(&stringp, ".");
2069 snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
2070 fdprint(ast_consock, tmp);
2071 snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
2072 fdprint(ast_consock, tmp);
2074 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2075 fdprint(ast_consock, tmp);
2077 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2078 remotehostname = hostname;
2080 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2081 if (el_hist == NULL || el == NULL)
2082 ast_el_initialize();
2084 el_set(el, EL_GETCFN, ast_el_read_char);
2086 if (!ast_strlen_zero(filename))
2087 ast_el_read_history(filename);
2089 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2092 fds.fd = ast_consock;
2093 fds.events = POLLIN;
2095 while (poll(&fds, 1, 100) > 0)
2096 ast_el_read_char(el, &tempchar);
2100 ebuf = (char *)el_gets(el, &num);
2102 if (!ast_strlen_zero(ebuf)) {
2103 if (ebuf[strlen(ebuf)-1] == '\n')
2104 ebuf[strlen(ebuf)-1] = '\0';
2105 if (!remoteconsolehandler(ebuf)) {
2106 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2108 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2114 printf("\nDisconnected from Asterisk server\n");
2117 static int show_version(void)
2119 printf("Asterisk " ASTERISK_VERSION "\n");
2123 static int show_cli_help(void) {
2124 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2125 printf("Usage: asterisk [OPTIONS]\n");
2126 printf("Valid Options:\n");
2127 printf(" -V Display version number and exit\n");
2128 printf(" -C <configfile> Use an alternate configuration file\n");
2129 printf(" -G <group> Run as a group other than the caller\n");
2130 printf(" -U <user> Run as a user other than the caller\n");
2131 printf(" -c Provide console CLI\n");
2132 printf(" -d Enable extra debugging\n");
2133 printf(" -f Do not fork\n");
2134 printf(" -g Dump core in case of a crash\n");
2135 printf(" -h This help screen\n");
2136 printf(" -i Initialize crypto keys at startup\n");
2137 printf(" -I Enable internal timing if Zaptel timer is available\n");
2138 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2139 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2140 printf(" -m Mute the console from debugging and verbose output\n");
2141 printf(" -n Disable console colorization\n");
2142 printf(" -p Run as pseudo-realtime thread\n");
2143 printf(" -q Quiet mode (suppress output)\n");
2144 printf(" -r Connect to Asterisk on this machine\n");
2145 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2146 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2147 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2148 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2149 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2154 static void ast_readconfig(void)
2156 struct ast_config *cfg;
2157 struct ast_variable *v;
2158 char *config = AST_CONFIG_FILE;
2160 if (ast_opt_override_config) {
2161 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2163 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2165 cfg = ast_config_load(config);
2168 /* init with buildtime config */
2169 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2170 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2171 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2172 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2173 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2174 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2175 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2176 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2177 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2178 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2179 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2180 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2181 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2183 /* no asterisk.conf? no problem, use buildtime config! */
2188 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2189 if (!strcasecmp(v->name, "astctlpermissions")) {
2190 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2191 } else if (!strcasecmp(v->name, "astctlowner")) {
2192 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2193 } else if (!strcasecmp(v->name, "astctlgroup")) {
2194 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2195 } else if (!strcasecmp(v->name, "astctl")) {
2196 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2200 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2201 if (!strcasecmp(v->name, "astetcdir")) {
2202 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2203 } else if (!strcasecmp(v->name, "astspooldir")) {
2204 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2205 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2206 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2207 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2208 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2209 } else if (!strcasecmp(v->name, "astdatadir")) {
2210 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2211 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2212 } else if (!strcasecmp(v->name, "astlogdir")) {
2213 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2214 } else if (!strcasecmp(v->name, "astagidir")) {
2215 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2216 } else if (!strcasecmp(v->name, "astrundir")) {
2217 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2218 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2219 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2220 } else if (!strcasecmp(v->name, "astmoddir")) {
2221 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2225 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2226 /* verbose level (-v at startup) */
2227 if (!strcasecmp(v->name, "verbose")) {
2228 option_verbose = atoi(v->value);
2229 /* whether or not to force timestamping. (-T at startup) */
2230 } else if (!strcasecmp(v->name, "timestamp")) {
2231 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2232 /* whether or not to support #exec in config files */
2233 } else if (!strcasecmp(v->name, "execincludes")) {
2234 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2235 /* debug level (-d at startup) */
2236 } else if (!strcasecmp(v->name, "debug")) {
2238 if (sscanf(v->value, "%d", &option_debug) != 1) {
2239 option_debug = ast_true(v->value);
2241 /* Disable forking (-f at startup) */
2242 } else if (!strcasecmp(v->name, "nofork")) {
2243 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2244 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2245 } else if (!strcasecmp(v->name, "alwaysfork")) {
2246 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2247 /* Run quietly (-q at startup ) */
2248 } else if (!strcasecmp(v->name, "quiet")) {
2249 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2250 /* Run as console (-c at startup, implies nofork) */
2251 } else if (!strcasecmp(v->name, "console")) {
2252 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2253 /* Run with high priority if the O/S permits (-p at startup) */
2254 } else if (!strcasecmp(v->name, "highpriority")) {
2255 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2256 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2257 } else if (!strcasecmp(v->name, "initcrypto")) {
2258 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2259 /* Disable ANSI colors for console (-c at startup) */
2260 } else if (!strcasecmp(v->name, "nocolor")) {
2261 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2262 /* Disable some usage warnings for picky people :p */
2263 } else if (!strcasecmp(v->name, "dontwarn")) {
2264 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2265 /* Dump core in case of crash (-g) */
2266 } else if (!strcasecmp(v->name, "dumpcore")) {
2267 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2268 /* Cache recorded sound files to another directory during recording */
2269 } else if (!strcasecmp(v->name, "cache_record_files")) {
2270 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2271 /* Specify cache directory */
2272 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2273 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2274 /* Build transcode paths via SLINEAR, instead of directly */
2275 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2276 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2277 /* Transmit SLINEAR silence while a channel is being recorded */
2278 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2279 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2280 /* Enable internal timing */
2281 } else if (!strcasecmp(v->name, "internal_timing")) {
2282 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2283 } else if (!strcasecmp(v->name, "maxcalls")) {
2284 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2285 option_maxcalls = 0;
2287 } else if (!strcasecmp(v->name, "maxload")) {
2290 if (getloadavg(test, 1) == -1) {
2291 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2292 option_maxload = 0.0;
2293 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2294 option_maxload = 0.0;
2296 /* What user to run as */
2297 } else if (!strcasecmp(v->name, "runuser")) {
2298 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2299 /* What group to run as */
2300 } else if (!strcasecmp(v->name, "rungroup")) {
2301 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2302 } else if (!strcasecmp(v->name, "systemname")) {
2303 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2304 } else if (!strcasecmp(v->name, "languageprefix")) {
2305 ast_language_is_prefix = ast_true(v->value);
2308 ast_config_destroy(cfg);
2311 int main(int argc, char *argv[])
2314 char filename[80] = "";
2315 char hostname[MAXHOSTNAMELEN] = "";
2322 int is_child_of_nonroot = 0;
2324 char *runuser = NULL, *rungroup = NULL;
2326 /* Remember original args for restart */
2327 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2328 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2329 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2331 for (x=0; x<argc; x++)
2335 /* if the progname is rasterisk consider it a remote console */
2336 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2337 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2339 if (gethostname(hostname, sizeof(hostname)-1))
2340 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2341 ast_mainpid = getpid();
2345 ast_builtins_init();
2348 /* When Asterisk restarts after it has dropped the root privileges,
2349 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2351 if (getenv("ASTERISK_ALREADY_NONROOT"))
2352 is_child_of_nonroot=1;
2354 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2355 /* Check for options */
2356 while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2359 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2363 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2366 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2369 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2372 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2375 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2378 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2381 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2385 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2388 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2391 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2392 option_maxcalls = 0;
2395 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2396 option_maxload = 0.0;
2399 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2402 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2405 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2408 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2412 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2413 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2416 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2419 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2422 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2441 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2442 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2443 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2446 /* For remote connections, change the name of the remote connection.
2447 * We do this for the benefit of init scripts (which need to know if/when
2448 * the main asterisk process has died yet). */
2449 if (ast_opt_remote) {
2450 strcpy(argv[0], "rasterisk");
2451 for (x = 1; x < argc; x++) {
2452 argv[x] = argv[0] + 10;
2456 if (ast_opt_console && !option_verbose)
2457 ast_verbose("[ Reading Master Configuration ]");
2460 if (ast_opt_dump_core) {
2462 memset(&l, 0, sizeof(l));
2463 l.rlim_cur = RLIM_INFINITY;
2464 l.rlim_max = RLIM_INFINITY;
2465 if (setrlimit(RLIMIT_CORE, &l)) {
2466 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2470 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2471 rungroup = ast_config_AST_RUN_GROUP;
2472 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2473 runuser = ast_config_AST_RUN_USER;
2477 if (!is_child_of_nonroot)
2478 ast_set_priority(ast_opt_high_priority);
2480 if (!is_child_of_nonroot && rungroup) {
2482 gr = getgrnam(rungroup);
2484 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2487 if (setgid(gr->gr_gid)) {
2488 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2491 if (setgroups(0, NULL)) {
2492 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2496 ast_verbose("Running as group '%s'\n", rungroup);
2499 if (!is_child_of_nonroot && runuser) {
2501 pw = getpwnam(runuser);
2503 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2507 if (setgid(pw->pw_gid)) {
2508 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2511 if (initgroups(pw->pw_name, pw->pw_gid)) {
2512 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2516 if (setuid(pw->pw_uid)) {
2517 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2520 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2522 ast_verbose("Running as user '%s'\n", runuser);
2525 #endif /* __CYGWIN__ */
2528 if (geteuid() && ast_opt_dump_core) {
2529 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2530 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2539 if (ast_opt_console && !option_verbose)
2540 ast_verbose("[ Initializing Custom Configuration Options ]");
2541 /* custom config setup */
2542 register_config_cli();
2545 if (ast_opt_console) {
2546 if (el_hist == NULL || el == NULL)
2547 ast_el_initialize();
2549 if (!ast_strlen_zero(filename))
2550 ast_el_read_history(filename);
2553 if (ast_tryconnect()) {
2554 /* One is already running */
2555 if (ast_opt_remote) {
2557 ast_remotecontrol(xarg);
2558 quit_handler(0, 0, 0, 0);
2561 printf(term_quit());
2562 ast_register_verbose(console_verboser);
2564 ast_remotecontrol(NULL);
2565 quit_handler(0, 0, 0, 0);
2568 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2569 printf(term_quit());
2572 } else if (ast_opt_remote || ast_opt_exec) {
2573 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2574 printf(term_quit());
2577 /* Blindly write pid file since we couldn't connect */
2578 unlink(ast_config_AST_PID);
2579 f = fopen(ast_config_AST_PID, "w");
2581 fprintf(f, "%ld\n", (long)getpid());
2584 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2586 if (ast_opt_always_fork || !ast_opt_no_fork) {
2588 ast_mainpid = getpid();
2589 /* Blindly re-write pid file since we are forking */
2590 unlink(ast_config_AST_PID);
2591 f = fopen(ast_config_AST_PID, "w");
2593 fprintf(f, "%ld\n", (long)ast_mainpid);
2596 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2599 /* Test recursive mutex locking. */
2600 if (test_for_thread_safety())
2601 ast_verbose("Warning! Asterisk is not thread safe.\n");
2605 sigaddset(&sigs, SIGHUP);
2606 sigaddset(&sigs, SIGTERM);
2607 sigaddset(&sigs, SIGINT);
2608 sigaddset(&sigs, SIGPIPE);
2609 sigaddset(&sigs, SIGWINCH);
2610 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2611 if (ast_opt_console || option_verbose || ast_opt_remote)
2612 ast_register_verbose(console_verboser);
2613 /* Print a welcome message if desired */
2614 if (option_verbose || ast_opt_console) {
2617 if (ast_opt_console && !option_verbose)
2618 ast_verbose("[ Booting...");
2620 signal(SIGURG, urg_handler);
2621 signal(SIGINT, __quit_handler);
2622 signal(SIGTERM, __quit_handler);
2623 signal(SIGHUP, hup_handler);
2624 signal(SIGCHLD, child_handler);
2625 signal(SIGPIPE, SIG_IGN);
2627 /* ensure that the random number generators are seeded with a different value every time
2630 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2631 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2633 if (init_logger()) {
2634 printf(term_quit());
2637 if (dnsmgr_init()) {
2638 printf(term_quit());
2641 /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2642 if (load_modules(1)) {
2643 printf(term_quit());
2647 ast_channels_init();
2648 if (init_manager()) {
2649 printf(term_quit());
2652 if (ast_cdr_engine_init()) {
2653 printf(term_quit());
2656 if (ast_device_state_engine_init()) {
2657 printf(term_quit());
2662 if (ast_image_init()) {
2663 printf(term_quit());
2666 if (ast_file_init()) {
2667 printf(term_quit());
2671 printf(term_quit());
2674 if (load_modules(0)) {
2675 printf(term_quit());
2678 if (init_framer()) {
2679 printf(term_quit());
2683 printf(term_quit());
2686 if (ast_enum_init()) {
2687 printf(term_quit());
2691 dnsmgr_start_refresh();
2694 /* This should no longer be necessary */
2695 /* sync cust config and reload some internals in case a custom config handler binded to them */
2696 read_ast_cust_config();
2703 /* We might have the option of showing a console, but for now just
2705 if (ast_opt_console && !option_verbose)
2706 ast_verbose(" ]\n");
2707 if (option_verbose || ast_opt_console)
2708 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2709 if (ast_opt_no_fork)
2710 consolethread = pthread_self();
2711 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2712 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2713 #ifdef __AST_DEBUG_MALLOC
2716 time(&ast_startuptime);
2717 ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2718 if (ast_opt_console) {
2719 /* Console stuff now... */
2720 /* Register our quit function */
2722 set_icon("Asterisk");
2723 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2727 buf = (char *)el_gets(el, &num);
2729 if (buf[strlen(buf)-1] == '\n')
2730 buf[strlen(buf)-1] = '\0';
2732 consolehandler((char *)buf);
2734 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2735 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2736 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2738 fd = open("/dev/null", O_RDWR);
2740 dup2(fd, STDOUT_FILENO);
2741 dup2(fd, STDIN_FILENO);
2743 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2751 for(;;) { /* apparently needed for the MACos */
2752 struct pollfd p = { -1 /* no descriptor */, 0, 0 };