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.
67 #include <sys/socket.h>
73 #include <sys/resource.h>
78 #include <sys/prctl.h>
83 #include <sys/prctl.h>
86 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
89 extern int daemon(int, int); /* defined in libresolv of all places */
95 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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 // XXX #include "asterisk/module.h"
105 #include "asterisk/image.h"
106 #include "asterisk/tdd.h"
107 #include "asterisk/term.h"
108 #include "asterisk/manager.h"
109 #include "asterisk/cdr.h"
110 #include "asterisk/pbx.h"
111 #include "asterisk/enum.h"
112 #include "asterisk/rtp.h"
113 #include "asterisk/http.h"
114 #if defined(T38_SUPPORT)
115 #include "asterisk/udptl.h"
117 #include "asterisk/app.h"
118 #include "asterisk/lock.h"
119 #include "asterisk/utils.h"
120 #include "asterisk/file.h"
121 #include "asterisk/io.h"
122 #include "asterisk/lock.h"
123 #include "editline/histedit.h"
124 #include "asterisk/config.h"
125 #include "asterisk/version.h"
126 #include "asterisk/linkedlists.h"
127 #include "asterisk/devicestate.h"
128 #include "asterisk/compat.h"
130 #include "asterisk/doxyref.h" /* Doxygen documentation */
132 #include "defaults.h"
135 #define AF_LOCAL AF_UNIX
136 #define PF_LOCAL PF_UNIX
139 #define AST_MAX_CONNECTS 128
142 /*! \brief Welcome message when starting a CLI interface */
143 #define WELCOME_MESSAGE \
144 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
145 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
146 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
147 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
148 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
149 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
150 ast_verbose("=========================================================================\n")
152 /*! \defgroup main_options
153 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
154 the operating system command line when starting Asterisk
155 Some of them can be changed in the CLI
159 extern int ast_language_is_prefix; /* XXX move to some header */
161 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
163 int option_verbose = 0; /*!< Verbosity level */
164 int option_debug = 0; /*!< Debug level */
166 double option_maxload = 0.0; /*!< Max load avg on system */
167 int option_maxcalls = 0; /*!< Max number of active calls */
171 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
172 char debug_filename[AST_FILENAME_MAX] = "";
174 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
175 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
178 int fd; /*!< File descriptor */
179 int p[2]; /*!< Pipe */
180 pthread_t t; /*!< Thread of handler */
185 AST_LIST_ENTRY(ast_atexit) list;
188 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
190 time_t ast_startuptime;
191 time_t ast_lastreloadtime;
193 static History *el_hist = NULL;
194 static EditLine *el = NULL;
195 static char *remotehostname;
197 struct console consoles[AST_MAX_CONNECTS];
199 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
201 static int ast_el_add_history(char *);
202 static int ast_el_read_history(char *);
203 static int ast_el_write_history(char *);
205 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
206 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
207 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
208 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
209 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
210 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
211 char ast_config_AST_DATA_DIR[AST_CONFIG_MAX_PATH];
212 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
213 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
214 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
215 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
216 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
217 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
218 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
219 char ast_config_AST_RUN_USER[AST_CONFIG_MAX_PATH];
220 char ast_config_AST_RUN_GROUP[AST_CONFIG_MAX_PATH];
221 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
222 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
223 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
224 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
225 char ast_config_AST_SYSTEM_NAME[20] = "";
227 extern const char *ast_build_hostname;
228 extern const char *ast_build_kernel;
229 extern const char *ast_build_machine;
230 extern const char *ast_build_os;
231 extern const char *ast_build_date;
232 extern const char *ast_build_user;
234 static char *_argv[256];
235 static int shuttingdown = 0;
236 static int restartnow = 0;
237 static pthread_t consolethread = AST_PTHREADT_NULL;
239 static char randompool[256];
241 #if !defined(LOW_MEMORY)
242 struct file_version {
243 AST_LIST_ENTRY(file_version) list;
248 static AST_LIST_HEAD_STATIC(file_versions, file_version);
250 void ast_register_file_version(const char *file, const char *version)
252 struct file_version *new;
254 size_t version_length;
256 work = ast_strdupa(version);
257 work = ast_strip(ast_strip_quoted(work, "$", "$"));
258 version_length = strlen(work) + 1;
260 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
264 new->version = (char *) new + sizeof(*new);
265 memcpy(new->version, work, version_length);
266 AST_LIST_LOCK(&file_versions);
267 AST_LIST_INSERT_HEAD(&file_versions, new, list);
268 AST_LIST_UNLOCK(&file_versions);
271 void ast_unregister_file_version(const char *file)
273 struct file_version *find;
275 AST_LIST_LOCK(&file_versions);
276 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
277 if (!strcasecmp(find->file, file)) {
278 AST_LIST_REMOVE_CURRENT(&file_versions, list);
282 AST_LIST_TRAVERSE_SAFE_END;
283 AST_LIST_UNLOCK(&file_versions);
288 struct thread_list_t {
289 AST_LIST_ENTRY(thread_list_t) list;
294 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
296 static char show_threads_help[] =
297 "Usage: show threads\n"
298 " List threads currently active in the system.\n";
300 void ast_register_thread(char *name)
302 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
306 new->id = pthread_self();
307 new->name = name; /* this was a copy already */
308 AST_LIST_LOCK(&thread_list);
309 AST_LIST_INSERT_HEAD(&thread_list, new, list);
310 AST_LIST_UNLOCK(&thread_list);
313 void ast_unregister_thread(void *id)
315 struct thread_list_t *x;
317 AST_LIST_LOCK(&thread_list);
318 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
319 if ((void *)x->id == id) {
320 AST_LIST_REMOVE_CURRENT(&thread_list, list);
324 AST_LIST_TRAVERSE_SAFE_END;
325 AST_LIST_UNLOCK(&thread_list);
332 static int handle_show_threads(int fd, int argc, char *argv[])
335 struct thread_list_t *cur;
337 AST_LIST_LOCK(&thread_list);
338 AST_LIST_TRAVERSE(&thread_list, cur, list) {
339 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
342 AST_LIST_UNLOCK(&thread_list);
343 ast_cli(fd, "%d threads listed.\n", count);
347 struct profile_entry {
349 uint64_t scale; /* if non-zero, values are scaled by this */
355 struct profile_data {
358 struct profile_entry e[0];
361 static struct profile_data *prof_data;
364 * allocates a counter with a given name and scale.
365 * Returns the identifier of the counter.
367 int ast_add_profile(const char *name, uint64_t scale)
369 int l = sizeof(struct profile_data);
370 int n = 10; /* default entries */
372 if (prof_data == NULL) {
373 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
374 if (prof_data == NULL)
376 prof_data->entries = 0;
377 prof_data->max_size = n;
379 if (prof_data->entries >= prof_data->max_size) {
381 n = prof_data->max_size + 20;
382 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
386 prof_data->max_size = n;
388 n = prof_data->entries++;
389 prof_data->e[n].name = ast_strdup(name);
390 prof_data->e[n].value = 0;
391 prof_data->e[n].events = 0;
392 prof_data->e[n].mark = 0;
393 prof_data->e[n].scale = scale;
397 int64_t ast_profile(int i, int64_t delta)
399 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
401 if (prof_data->e[i].scale > 1)
402 delta /= prof_data->e[i].scale;
403 prof_data->e[i].value += delta;
404 prof_data->e[i].events++;
405 return prof_data->e[i].value;
408 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
409 #if defined(__FreeBSD__)
410 #include <machine/cpufunc.h>
412 static __inline u_int64_t
417 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
421 #else /* supply a dummy function on other platforms */
422 static __inline u_int64_t
429 int64_t ast_mark(int i, int startstop)
431 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
434 prof_data->e[i].mark = rdtsc();
436 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
437 if (prof_data->e[i].scale > 1)
438 prof_data->e[i].mark /= prof_data->e[i].scale;
439 prof_data->e[i].value += prof_data->e[i].mark;
440 prof_data->e[i].events++;
442 return prof_data->e[i].mark;
445 static int handle_show_profile(int fd, int argc, char *argv[])
450 if (prof_data == NULL)
454 max = prof_data->entries;
455 if (argc >= 3) { /* specific entries */
456 if (isdigit(argv[2][0])) {
458 if (argc == 4 && strcmp(argv[3], "-"))
463 if (max > prof_data->entries)
464 max = prof_data->entries;
465 if (!strcmp(argv[0], "clear")) {
466 for (i= min; i < max; i++) {
467 if (!search || strstr(prof_data->e[i].name, search)) {
468 prof_data->e[i].value = 0;
469 prof_data->e[i].events = 0;
474 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
475 prof_data->entries, prof_data->max_size);
476 for (i = min; i < max; i++) {
477 struct profile_entry *e = &prof_data->e[i];
478 if (!search || strstr(prof_data->e[i].name, search))
479 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
482 (long)e->events, (long long)e->value,
483 (long long)(e->events ? e->value / e->events : e->value),
489 static char show_version_files_help[] =
490 "Usage: show version files [like <pattern>]\n"
491 " Shows the revision numbers of the files used to build this copy of Asterisk.\n"
492 " Optional regular expression pattern is used to filter the file list.\n";
494 /*! CLI command to list module versions */
495 static int handle_show_version_files(int fd, int argc, char *argv[])
497 #define FORMAT "%-25.25s %-40.40s\n"
498 struct file_version *iterator;
506 if (!strcasecmp(argv[3], "like")) {
507 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
508 return RESULT_SHOWUSAGE;
511 return RESULT_SHOWUSAGE;
519 return RESULT_SHOWUSAGE;
522 ast_cli(fd, FORMAT, "File", "Revision");
523 ast_cli(fd, FORMAT, "----", "--------");
524 AST_LIST_LOCK(&file_versions);
525 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
526 if (havename && strcasecmp(iterator->file, argv[3]))
529 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
532 ast_cli(fd, FORMAT, iterator->file, iterator->version);
537 AST_LIST_UNLOCK(&file_versions);
539 ast_cli(fd, "%d files listed.\n", count_files);
545 return RESULT_SUCCESS;
549 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
551 struct file_version *find;
554 int matchlen = strlen(word);
559 AST_LIST_LOCK(&file_versions);
560 AST_LIST_TRAVERSE(&file_versions, find, list) {
561 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
562 ret = ast_strdup(find->file);
566 AST_LIST_UNLOCK(&file_versions);
570 #endif /* ! LOW_MEMORY */
572 int ast_register_atexit(void (*func)(void))
575 struct ast_atexit *ae;
576 ast_unregister_atexit(func);
577 AST_LIST_LOCK(&atexits);
578 if ((ae = ast_calloc(1, sizeof(*ae)))) {
579 AST_LIST_INSERT_HEAD(&atexits, ae, list);
583 AST_LIST_UNLOCK(&atexits);
587 void ast_unregister_atexit(void (*func)(void))
589 struct ast_atexit *ae;
590 AST_LIST_LOCK(&atexits);
591 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
592 if (ae->func == func) {
593 AST_LIST_REMOVE_CURRENT(&atexits, list);
597 AST_LIST_TRAVERSE_SAFE_END
598 AST_LIST_UNLOCK(&atexits);
601 static int fdprint(int fd, const char *s)
603 return write(fd, s, strlen(s) + 1);
606 /*! NULL handler so we can collect the child exit status */
607 static void null_sig_handler(int signal)
612 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
613 static unsigned int safe_system_level = 0;
614 static void *safe_system_prev_handler;
616 int ast_safe_system(const char *s)
621 struct rusage rusage;
625 /* keep track of how many ast_safe_system() functions
626 are running at this moment
628 ast_mutex_lock(&safe_system_lock);
629 level = safe_system_level++;
631 /* only replace the handler if it has not already been done */
633 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
635 ast_mutex_unlock(&safe_system_lock);
640 /* Close file descriptors and launch system command */
641 for (x = STDERR_FILENO + 1; x < 4096; x++)
643 execl("/bin/sh", "/bin/sh", "-c", s, NULL);
645 } else if (pid > 0) {
647 res = wait4(pid, &status, 0, &rusage);
649 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
651 } else if (errno != EINTR)
655 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
659 ast_mutex_lock(&safe_system_lock);
660 level = --safe_system_level;
662 /* only restore the handler if we are the last one */
664 signal(SIGCHLD, safe_system_prev_handler);
666 ast_mutex_unlock(&safe_system_lock);
672 * write the string to all attached console clients
674 static void ast_network_puts(const char *string)
677 for (x=0; x < AST_MAX_CONNECTS; x++) {
678 if (consoles[x].fd > -1)
679 fdprint(consoles[x].p[1], string);
684 * write the string to the console, and all attached
687 void ast_console_puts(const char *string)
689 fputs(string, stdout);
691 ast_network_puts(string);
694 static void network_verboser(const char *s, int pos, int replace, int complete)
699 if ((t = alloca(strlen(s) + 2))) {
700 sprintf(t, "\r%s", s);
704 ast_log(LOG_ERROR, "Out of memory\n");
713 static pthread_t lthread;
715 static void *netconsole(void *vconsole)
717 struct console *con = vconsole;
718 char hostname[MAXHOSTNAMELEN] = "";
721 struct pollfd fds[2];
723 if (gethostname(hostname, sizeof(hostname)-1))
724 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
725 snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
726 fdprint(con->fd, tmp);
729 fds[0].events = POLLIN;
731 fds[1].fd = con->p[0];
732 fds[1].events = POLLIN;
735 res = poll(fds, 2, -1);
738 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
741 if (fds[0].revents) {
742 res = read(con->fd, tmp, sizeof(tmp));
747 ast_cli_command(con->fd, tmp);
749 if (fds[1].revents) {
750 res = read(con->p[0], tmp, sizeof(tmp));
752 ast_log(LOG_ERROR, "read returned %d\n", res);
755 res = write(con->fd, tmp, res);
760 if (option_verbose > 2)
761 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
770 static void *listener(void *unused)
772 struct sockaddr_un sunaddr;
777 struct pollfd fds[1];
779 pthread_attr_init(&attr);
780 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
784 fds[0].fd = ast_socket;
785 fds[0].events = POLLIN;
786 s = poll(fds, 1, -1);
789 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
792 len = sizeof(sunaddr);
793 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
796 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
798 for (x = 0; x < AST_MAX_CONNECTS; x++) {
799 if (consoles[x].fd < 0) {
800 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
801 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
803 fdprint(s, "Server failed to create pipe\n");
807 flags = fcntl(consoles[x].p[1], F_GETFL);
808 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
810 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
811 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
812 close(consoles[x].p[0]);
813 close(consoles[x].p[1]);
815 fdprint(s, "Server failed to spawn thread\n");
821 if (x >= AST_MAX_CONNECTS) {
822 fdprint(s, "No more connections allowed\n");
823 ast_log(LOG_WARNING, "No more connections allowed\n");
825 } else if (consoles[x].fd > -1) {
826 if (option_verbose > 2)
827 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
834 static int ast_makesocket(void)
836 struct sockaddr_un sunaddr;
842 for (x = 0; x < AST_MAX_CONNECTS; x++)
844 unlink(ast_config_AST_SOCKET);
845 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
846 if (ast_socket < 0) {
847 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
850 memset(&sunaddr, 0, sizeof(sunaddr));
851 sunaddr.sun_family = AF_LOCAL;
852 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
853 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
855 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
860 res = listen(ast_socket, 2);
862 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
867 ast_register_verbose(network_verboser);
868 ast_pthread_create(<hread, NULL, listener, NULL);
870 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
872 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
873 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
879 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
881 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
882 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
888 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
889 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
891 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
894 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
896 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
897 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
903 static int ast_tryconnect(void)
905 struct sockaddr_un sunaddr;
907 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
908 if (ast_consock < 0) {
909 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
912 memset(&sunaddr, 0, sizeof(sunaddr));
913 sunaddr.sun_family = AF_LOCAL;
914 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
915 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
925 Called by soft_hangup to interrupt the poll, read, or other
926 system call. We don't actually need to do anything though.
927 Remember: Cannot EVER ast_log from within a signal handler
928 SLD: seems to be some pthread activity relating to the printf anyway:
929 which is leading to a deadlock?
931 static void urg_handler(int num)
934 if (option_debug > 2)
935 printf("-- Asterisk Urgent handler\n");
937 signal(num, urg_handler);
941 static void hup_handler(int num)
943 if (option_verbose > 1)
944 printf("Received HUP signal -- Reloading configs\n");
946 execvp(_argv[0], _argv);
947 /* XXX This could deadlock XXX */
948 ast_module_reload(NULL);
949 signal(num, hup_handler);
952 static void child_handler(int sig)
954 /* Must not ever ast_log or ast_verbose within signal handler */
958 * Reap all dead children -- not just one
960 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
962 if (n == 0 && option_debug)
963 printf("Huh? Child handler, but nobody there?\n");
964 signal(sig, child_handler);
967 /*! Set an X-term or screen title */
968 static void set_title(char *text)
970 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
971 fprintf(stdout, "\033]2;%s\007", text);
974 static void set_icon(char *text)
976 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
977 fprintf(stdout, "\033]1;%s\007", text);
980 /*! We set ourselves to a high priority, that we might pre-empt everything
981 else. If your PBX has heavy activity on it, this is a good thing. */
982 int ast_set_priority(int pri)
984 struct sched_param sched;
985 memset(&sched, 0, sizeof(sched));
988 sched.sched_priority = 10;
989 if (sched_setscheduler(0, SCHED_RR, &sched)) {
990 ast_log(LOG_WARNING, "Unable to set high priority\n");
994 ast_verbose("Set to realtime thread\n");
996 sched.sched_priority = 0;
997 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
998 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1004 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1005 ast_log(LOG_WARNING, "Unable to set high priority\n");
1009 ast_verbose("Set to high priority\n");
1011 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1012 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1020 static void ast_run_atexits(void)
1022 struct ast_atexit *ae;
1023 AST_LIST_LOCK(&atexits);
1024 AST_LIST_TRAVERSE(&atexits, ae, list) {
1028 AST_LIST_UNLOCK(&atexits);
1031 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1033 char filename[80] = "";
1036 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1037 ast_cdr_engine_term();
1041 /* Begin shutdown routine, hanging up active channels */
1042 ast_begin_shutdown(1);
1043 if (option_verbose && ast_opt_console)
1044 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1048 /* Wait up to 15 seconds for all channels to go away */
1051 if (!ast_active_channels())
1055 /* Sleep 1/10 of a second */
1060 ast_begin_shutdown(0);
1061 if (option_verbose && ast_opt_console)
1062 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1064 if (!ast_active_channels())
1072 if (!shuttingdown) {
1073 if (option_verbose && ast_opt_console)
1074 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1078 if (ast_opt_console || ast_opt_remote) {
1080 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1081 if (!ast_strlen_zero(filename))
1082 ast_el_write_history(filename);
1085 if (el_hist != NULL)
1086 history_end(el_hist);
1089 ast_verbose("Executing last minute cleanups\n");
1091 /* Called on exit */
1092 if (option_verbose && ast_opt_console)
1093 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1094 else if (option_debug)
1095 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1096 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1097 if (ast_socket > -1) {
1100 unlink(ast_config_AST_SOCKET);
1101 pthread_cancel(lthread);
1103 if (ast_consock > -1)
1105 if (!ast_opt_remote)
1106 unlink(ast_config_AST_PID);
1107 printf(term_quit());
1109 if (option_verbose || ast_opt_console)
1110 ast_verbose("Preparing for Asterisk restart...\n");
1111 /* Mark all FD's for closing on exec */
1112 for (x=3; x < 32768; x++) {
1113 fcntl(x, F_SETFD, FD_CLOEXEC);
1115 if (option_verbose || ast_opt_console)
1116 ast_verbose("Restarting Asterisk NOW...\n");
1122 /* If there is a consolethread running send it a SIGHUP
1123 so it can execvp, otherwise we can do it ourselves */
1124 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1125 pthread_kill(consolethread, SIGHUP);
1126 /* Give the signal handler some time to complete */
1129 execvp(_argv[0], _argv);
1138 static void __quit_handler(int num)
1140 quit_handler(num, 0, 1, 0);
1143 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1146 if (!strncmp(s, cmp, strlen(cmp))) {
1147 c = s + strlen(cmp);
1148 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1154 static void console_verboser(const char *s, int pos, int replace, int complete)
1157 const char *c = NULL;
1158 /* Return to the beginning of the line */
1160 fprintf(stdout, "\r");
1161 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1162 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1163 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1164 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
1168 fputs(c + pos,stdout);
1170 fputs(s + pos,stdout);
1173 /* Wake up a poll()ing console */
1174 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1175 pthread_kill(consolethread, SIGURG);
1179 static int ast_all_zeros(char *s)
1189 static void consolehandler(char *s)
1193 /* Called when readline data is available */
1194 if (s && !ast_all_zeros(s))
1195 ast_el_add_history(s);
1196 /* Give the console access to the shell */
1198 /* The real handler for bang */
1201 ast_safe_system(s+1);
1203 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1205 ast_cli_command(STDOUT_FILENO, s);
1207 fprintf(stdout, "\nUse \"quit\" to exit\n");
1210 static int remoteconsolehandler(char *s)
1213 /* Called when readline data is available */
1214 if (s && !ast_all_zeros(s))
1215 ast_el_add_history(s);
1216 /* Give the console access to the shell */
1218 /* The real handler for bang */
1221 ast_safe_system(s+1);
1223 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1226 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1227 (s[4] == '\0' || isspace(s[4]))) {
1228 quit_handler(0, 0, 0, 0);
1232 fprintf(stdout, "\nUse \"quit\" to exit\n");
1237 static char abort_halt_help[] =
1238 "Usage: abort shutdown\n"
1239 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1240 " call operations.\n";
1242 static char shutdown_now_help[] =
1244 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1246 static char shutdown_gracefully_help[] =
1247 "Usage: stop gracefully\n"
1248 " Causes Asterisk to not accept new calls, and exit when all\n"
1249 " active calls have terminated normally.\n";
1251 static char shutdown_when_convenient_help[] =
1252 "Usage: stop when convenient\n"
1253 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1255 static char restart_now_help[] =
1256 "Usage: restart now\n"
1257 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1260 static char restart_gracefully_help[] =
1261 "Usage: restart gracefully\n"
1262 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1263 " restart when all active calls have ended.\n";
1265 static char restart_when_convenient_help[] =
1266 "Usage: restart when convenient\n"
1267 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1269 static char bang_help[] =
1270 "Usage: !<command>\n"
1271 " Executes a given shell command\n";
1273 static char show_warranty_help[] =
1274 "Usage: show warranty\n"
1275 " Shows the warranty (if any) for this copy of Asterisk.\n";
1277 static char show_license_help[] =
1278 "Usage: show license\n"
1279 " Shows the license(s) for this copy of Asterisk.\n";
1281 static char version_help[] =
1282 "Usage: show version\n"
1283 " Shows Asterisk version information.\n";
1285 static int handle_version(int fd, int argc, char *argv[])
1288 return RESULT_SHOWUSAGE;
1289 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1290 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1291 ast_build_machine, ast_build_os, ast_build_date);
1292 return RESULT_SUCCESS;
1296 static int handle_quit(int fd, int argc, char *argv[])
1299 return RESULT_SHOWUSAGE;
1300 quit_handler(0, 0, 1, 0);
1301 return RESULT_SUCCESS;
1305 static int handle_shutdown_now(int fd, int argc, char *argv[])
1308 return RESULT_SHOWUSAGE;
1309 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1310 return RESULT_SUCCESS;
1313 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1316 return RESULT_SHOWUSAGE;
1317 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1318 return RESULT_SUCCESS;
1321 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1324 return RESULT_SHOWUSAGE;
1325 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1326 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1327 return RESULT_SUCCESS;
1330 static int handle_restart_now(int fd, int argc, char *argv[])
1333 return RESULT_SHOWUSAGE;
1334 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1335 return RESULT_SUCCESS;
1338 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1341 return RESULT_SHOWUSAGE;
1342 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1343 return RESULT_SUCCESS;
1346 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1349 return RESULT_SHOWUSAGE;
1350 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1351 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1352 return RESULT_SUCCESS;
1355 static int handle_abort_halt(int fd, int argc, char *argv[])
1358 return RESULT_SHOWUSAGE;
1359 ast_cancel_shutdown();
1361 return RESULT_SUCCESS;
1364 static int handle_bang(int fd, int argc, char *argv[])
1366 return RESULT_SUCCESS;
1368 static const char *warranty_lines[] = {
1372 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1373 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1374 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1375 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1376 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1377 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1378 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1379 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1380 "REPAIR OR CORRECTION.\n",
1382 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1383 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1384 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1385 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1386 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1387 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1388 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1389 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1390 "POSSIBILITY OF SUCH DAMAGES.\n",
1393 static int show_warranty(int fd, int argc, char *argv[])
1397 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1398 ast_cli(fd, (char *) warranty_lines[x]);
1400 return RESULT_SUCCESS;
1403 static const char *license_lines[] = {
1405 "This program is free software; you can redistribute it and/or modify\n",
1406 "it under the terms of the GNU General Public License version 2 as\n",
1407 "published by the Free Software Foundation.\n",
1409 "This program also contains components licensed under other licenses.\n",
1412 "This program is distributed in the hope that it will be useful,\n",
1413 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1414 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1415 "GNU General Public License for more details.\n",
1417 "You should have received a copy of the GNU General Public License\n",
1418 "along with this program; if not, write to the Free Software\n",
1419 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1422 static int show_license(int fd, int argc, char *argv[])
1426 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1427 ast_cli(fd, (char *) license_lines[x]);
1429 return RESULT_SUCCESS;
1432 #define ASTERISK_PROMPT "*CLI> "
1434 #define ASTERISK_PROMPT2 "%s*CLI> "
1436 static struct ast_cli_entry core_cli[] = {
1437 { { "abort", "halt", NULL }, handle_abort_halt,
1438 "Cancel a running halt", abort_halt_help },
1439 { { "stop", "now", NULL }, handle_shutdown_now,
1440 "Shut down Asterisk immediately", shutdown_now_help },
1441 { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1442 "Gracefully shut down Asterisk", shutdown_gracefully_help },
1443 { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1444 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1445 { { "restart", "now", NULL }, handle_restart_now,
1446 "Restart Asterisk immediately", restart_now_help },
1447 { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1448 "Restart Asterisk gracefully", restart_gracefully_help },
1449 { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1450 "Restart Asterisk at empty call volume", restart_when_convenient_help },
1451 { { "show", "warranty", NULL }, show_warranty,
1452 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
1453 { { "show", "license", NULL }, show_license,
1454 "Show the license(s) for this copy of Asterisk", show_license_help },
1455 { { "show", "version", NULL }, handle_version,
1456 "Display version info", version_help },
1457 { { "!", NULL }, handle_bang,
1458 "Execute a shell command", bang_help },
1459 #if !defined(LOW_MEMORY)
1460 { { "show", "version", "files", NULL }, handle_show_version_files,
1461 "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1462 { { "show", "threads", NULL }, handle_show_threads,
1463 "Show running threads", show_threads_help, NULL },
1464 { { "show", "profile", NULL }, handle_show_profile,
1465 "Show profiling info"},
1466 { { "clear", "profile", NULL }, handle_show_profile,
1467 "Clear profiling info"},
1468 #endif /* ! LOW_MEMORY */
1471 static int ast_el_read_char(EditLine *el, char *cp)
1475 struct pollfd fds[2];
1482 fds[0].fd = ast_consock;
1483 fds[0].events = POLLIN;
1484 if (!ast_opt_exec) {
1485 fds[1].fd = STDIN_FILENO;
1486 fds[1].events = POLLIN;
1489 res = poll(fds, max, -1);
1493 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1497 if (!ast_opt_exec && fds[1].revents) {
1498 num_read = read(STDIN_FILENO, cp, 1);
1504 if (fds[0].revents) {
1505 res = read(ast_consock, buf, sizeof(buf) - 1);
1506 /* if the remote side disappears exit */
1508 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1509 if (!ast_opt_reconnect) {
1510 quit_handler(0, 0, 0, 0);
1513 int reconnects_per_second = 20;
1514 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1515 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1516 if (ast_tryconnect()) {
1517 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1518 printf(term_quit());
1522 usleep(1000000 / reconnects_per_second);
1525 if (tries >= 30 * reconnects_per_second) {
1526 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1527 quit_handler(0, 0, 0, 0);
1534 if (!ast_opt_exec && !lastpos)
1535 write(STDOUT_FILENO, "\r", 1);
1536 write(STDOUT_FILENO, buf, res);
1537 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1550 static char *cli_prompt(EditLine *el)
1552 static char prompt[200];
1557 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1558 char *t = pfmt, *p = prompt;
1559 memset(prompt, 0, sizeof(prompt));
1560 while (*t != '\0' && *p < sizeof(prompt)) {
1562 char hostname[MAXHOSTNAMELEN]="";
1569 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1573 case 'C': /* color */
1575 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1576 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1578 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1579 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1583 /* If the color has been reset correctly, then there's no need to reset it later */
1584 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1590 case 'd': /* date */
1591 memset(&tm, 0, sizeof(tm));
1593 if (localtime_r(&ts, &tm)) {
1594 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1597 case 'h': /* hostname */
1598 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1599 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1601 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1604 case 'H': /* short hostname */
1605 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1606 for (i = 0; i < sizeof(hostname); i++) {
1607 if (hostname[i] == '.') {
1612 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1614 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1618 case 'l': /* load avg */
1620 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1621 float avg1, avg2, avg3;
1622 int actproc, totproc, npid, which;
1623 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1624 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1625 if (sscanf(t, "%d", &which) == 1) {
1628 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1631 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1634 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1637 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1640 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1647 case 't': /* time */
1648 memset(&tm, 0, sizeof(tm));
1650 if (localtime_r(&ts, &tm)) {
1651 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1654 case '#': /* process console or remote? */
1655 if (!ast_opt_remote) {
1656 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1658 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1661 case '%': /* literal % */
1662 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1664 case '\0': /* % is last character - prevent bug */
1668 while (*p != '\0') {
1679 /* Force colors back to normal at end */
1680 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1681 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1682 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1684 strncat(p, term_code, sizeof(term_code));
1687 } else if (remotehostname)
1688 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1690 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1695 static char **ast_el_strtoarr(char *buf)
1697 char **match_list = NULL, *retstr;
1698 size_t match_list_len;
1702 while ( (retstr = strsep(&buf, " ")) != NULL) {
1704 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1706 if (matches + 1 >= match_list_len) {
1707 match_list_len <<= 1;
1708 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1709 /* TODO: Handle memory allocation failure */
1713 match_list[matches++] = strdup(retstr);
1717 return (char **) NULL;
1719 if (matches >= match_list_len) {
1720 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1721 /* TODO: Handle memory allocation failure */
1725 match_list[matches] = (char *) NULL;
1730 static int ast_el_sort_compare(const void *i1, const void *i2)
1734 s1 = ((char **)i1)[0];
1735 s2 = ((char **)i2)[0];
1737 return strcasecmp(s1, s2);
1740 static int ast_cli_display_match_list(char **matches, int len, int max)
1742 int i, idx, limit, count;
1743 int screenwidth = 0;
1744 int numoutput = 0, numoutputline = 0;
1746 screenwidth = ast_get_termcols(STDOUT_FILENO);
1748 /* find out how many entries can be put on one line, with two spaces between strings */
1749 limit = screenwidth / (max + 2);
1753 /* how many lines of output */
1754 count = len / limit;
1755 if (count * limit < len)
1760 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1762 for (; count > 0; count--) {
1764 for (i=0; i < limit && matches[idx]; i++, idx++) {
1766 /* Don't print dupes */
1767 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1770 matches[idx] = NULL;
1776 fprintf(stdout, "%-*s ", max, matches[idx]);
1778 matches[idx] = NULL;
1780 if (numoutputline > 0)
1781 fprintf(stdout, "\n");
1788 static char *cli_complete(EditLine *el, int ch)
1794 int retval = CC_ERROR;
1798 LineInfo *lf = (LineInfo *)el_line(el);
1800 *(char *)lf->cursor = '\0';
1801 ptr = (char *)lf->cursor;
1803 while (ptr > lf->buffer) {
1804 if (isspace(*ptr)) {
1812 len = lf->cursor - ptr;
1814 if (ast_opt_remote) {
1815 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1816 fdprint(ast_consock, buf);
1817 res = read(ast_consock, buf, sizeof(buf));
1819 nummatches = atoi(buf);
1821 if (nummatches > 0) {
1823 int mlen = 0, maxmbuf = 2048;
1824 /* Start with a 2048 byte buffer */
1825 if (!(mbuf = ast_malloc(maxmbuf)))
1826 return (char *)(CC_ERROR);
1827 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1828 fdprint(ast_consock, buf);
1831 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1832 if (mlen + 1024 > maxmbuf) {
1833 /* Every step increment buffer 1024 bytes */
1835 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1836 return (char *)(CC_ERROR);
1838 /* Only read 1024 bytes at a time */
1839 res = read(ast_consock, mbuf + mlen, 1024);
1845 matches = ast_el_strtoarr(mbuf);
1848 matches = (char **) NULL;
1850 char **p, *oldbuf=NULL;
1852 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1853 for (p = matches; p && *p; p++) {
1854 if (!oldbuf || strcmp(*p,oldbuf))
1862 int matches_num, maxlen, match_len;
1864 if (matches[0][0] != '\0') {
1865 el_deletestr(el, (int) len);
1866 el_insertstr(el, matches[0]);
1867 retval = CC_REFRESH;
1870 if (nummatches == 1) {
1871 /* Found an exact match */
1872 el_insertstr(el, " ");
1873 retval = CC_REFRESH;
1875 /* Must be more than one match */
1876 for (i=1, maxlen=0; matches[i]; i++) {
1877 match_len = strlen(matches[i]);
1878 if (match_len > maxlen)
1881 matches_num = i - 1;
1882 if (matches_num >1) {
1883 fprintf(stdout, "\n");
1884 ast_cli_display_match_list(matches, nummatches, maxlen);
1885 retval = CC_REDISPLAY;
1887 el_insertstr(el," ");
1888 retval = CC_REFRESH;
1894 return (char *)(long)retval;
1897 static int ast_el_initialize(void)
1900 char *editor = getenv("AST_EDITOR");
1904 if (el_hist != NULL)
1905 history_end(el_hist);
1907 el = el_init("asterisk", stdin, stdout, stderr);
1908 el_set(el, EL_PROMPT, cli_prompt);
1910 el_set(el, EL_EDITMODE, 1);
1911 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1912 el_hist = history_init();
1913 if (!el || !el_hist)
1916 /* setup history with 100 entries */
1917 history(el_hist, &ev, H_SETSIZE, 100);
1919 el_set(el, EL_HIST, history, el_hist);
1921 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1922 /* Bind <tab> to command completion */
1923 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1924 /* Bind ? to command completion */
1925 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1926 /* Bind ^D to redisplay */
1927 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1932 static int ast_el_add_history(char *buf)
1936 if (el_hist == NULL || el == NULL)
1937 ast_el_initialize();
1938 if (strlen(buf) > 256)
1940 return (history(el_hist, &ev, H_ENTER, buf));
1943 static int ast_el_write_history(char *filename)
1947 if (el_hist == NULL || el == NULL)
1948 ast_el_initialize();
1950 return (history(el_hist, &ev, H_SAVE, filename));
1953 static int ast_el_read_history(char *filename)
1959 if (el_hist == NULL || el == NULL)
1960 ast_el_initialize();
1962 if ((f = fopen(filename, "r")) == NULL)
1966 fgets(buf, sizeof(buf), f);
1967 if (!strcmp(buf, "_HiStOrY_V2_\n"))
1969 if (ast_all_zeros(buf))
1971 if ((ret = ast_el_add_history(buf)) == -1)
1979 static void ast_remotecontrol(char * data)
1983 char filename[80] = "";
1989 char *stringp = NULL;
1994 read(ast_consock, buf, sizeof(buf));
1996 write(ast_consock, data, strlen(data) + 1);
1998 hostname = strsep(&stringp, "/");
1999 cpid = strsep(&stringp, "/");
2000 version = strsep(&stringp, "\n");
2002 version = "<Version Unknown>";
2004 strsep(&stringp, ".");
2009 snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
2010 fdprint(ast_consock, tmp);
2011 snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
2012 fdprint(ast_consock, tmp);
2013 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2014 remotehostname = hostname;
2016 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2017 if (el_hist == NULL || el == NULL)
2018 ast_el_initialize();
2020 el_set(el, EL_GETCFN, ast_el_read_char);
2022 if (!ast_strlen_zero(filename))
2023 ast_el_read_history(filename);
2025 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2027 struct pollfd fds[0];
2028 fds[0].fd = ast_consock;
2029 fds[0].events = POLLIN;
2031 while(poll(fds, 1, 100) > 0) {
2032 ast_el_read_char(el, &tempchar);
2037 ebuf = (char *)el_gets(el, &num);
2039 if (!ast_strlen_zero(ebuf)) {
2040 if (ebuf[strlen(ebuf)-1] == '\n')
2041 ebuf[strlen(ebuf)-1] = '\0';
2042 if (!remoteconsolehandler(ebuf)) {
2043 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2045 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2051 printf("\nDisconnected from Asterisk server\n");
2054 static int show_version(void)
2056 printf("Asterisk " ASTERISK_VERSION "\n");
2060 static int show_cli_help(void) {
2061 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2062 printf("Usage: asterisk [OPTIONS]\n");
2063 printf("Valid Options:\n");
2064 printf(" -V Display version number and exit\n");
2065 printf(" -C <configfile> Use an alternate configuration file\n");
2066 printf(" -G <group> Run as a group other than the caller\n");
2067 printf(" -U <user> Run as a user other than the caller\n");
2068 printf(" -c Provide console CLI\n");
2069 printf(" -d Enable extra debugging\n");
2070 printf(" -f Do not fork\n");
2071 printf(" -g Dump core in case of a crash\n");
2072 printf(" -h This help screen\n");
2073 printf(" -i Initialize crypto keys at startup\n");
2074 printf(" -I Enable internal timing if Zaptel timer is available\n");
2075 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2076 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2077 printf(" -n Disable console colorization\n");
2078 printf(" -p Run as pseudo-realtime thread\n");
2079 printf(" -q Quiet mode (suppress output)\n");
2080 printf(" -r Connect to Asterisk on this machine\n");
2081 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2082 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2083 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2084 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2085 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2090 static void ast_readconfig(void)
2092 struct ast_config *cfg;
2093 struct ast_variable *v;
2094 char *config = AST_CONFIG_FILE;
2096 if (ast_opt_override_config) {
2097 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2099 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2101 cfg = ast_config_load(config);
2104 /* init with buildtime config */
2105 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2106 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2107 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2108 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2109 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2110 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2111 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2112 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2113 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2114 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2115 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2116 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2117 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2119 /* no asterisk.conf? no problem, use buildtime config! */
2123 v = ast_variable_browse(cfg, "files");
2125 if (!strcasecmp(v->name, "astctlpermissions")) {
2126 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2127 } else if (!strcasecmp(v->name, "astctlowner")) {
2128 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2129 } else if (!strcasecmp(v->name, "astctlgroup")) {
2130 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2131 } else if (!strcasecmp(v->name, "astctl")) {
2132 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2136 v = ast_variable_browse(cfg, "directories");
2138 if (!strcasecmp(v->name, "astetcdir")) {
2139 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2140 } else if (!strcasecmp(v->name, "astspooldir")) {
2141 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2142 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2143 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2144 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2145 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2146 } else if (!strcasecmp(v->name, "astdatadir")) {
2147 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2148 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2149 } else if (!strcasecmp(v->name, "astlogdir")) {
2150 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2151 } else if (!strcasecmp(v->name, "astagidir")) {
2152 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2153 } else if (!strcasecmp(v->name, "astrundir")) {
2154 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2155 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2156 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2157 } else if (!strcasecmp(v->name, "astmoddir")) {
2158 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2159 } else if (!strcasecmp(v->name, "languageprefix")) {
2160 ast_language_is_prefix = ast_true(v->value);
2164 v = ast_variable_browse(cfg, "options");
2166 /* verbose level (-v at startup) */
2167 if (!strcasecmp(v->name, "verbose")) {
2168 option_verbose = atoi(v->value);
2169 /* whether or not to force timestamping. (-T at startup) */
2170 } else if (!strcasecmp(v->name, "timestamp")) {
2171 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2172 /* whether or not to support #exec in config files */
2173 } else if (!strcasecmp(v->name, "execincludes")) {
2174 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2175 /* debug level (-d at startup) */
2176 } else if (!strcasecmp(v->name, "debug")) {
2178 if (sscanf(v->value, "%d", &option_debug) != 1) {
2179 option_debug = ast_true(v->value);
2181 /* Disable forking (-f at startup) */
2182 } else if (!strcasecmp(v->name, "nofork")) {
2183 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2184 /* Run quietly (-q at startup ) */
2185 } else if (!strcasecmp(v->name, "quiet")) {
2186 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2187 /* Run as console (-c at startup, implies nofork) */
2188 } else if (!strcasecmp(v->name, "console")) {
2189 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2190 /* Run with high priority if the O/S permits (-p at startup) */
2191 } else if (!strcasecmp(v->name, "highpriority")) {
2192 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2193 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2194 } else if (!strcasecmp(v->name, "initcrypto")) {
2195 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2196 /* Disable ANSI colors for console (-c at startup) */
2197 } else if (!strcasecmp(v->name, "nocolor")) {
2198 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2199 /* Disable some usage warnings for picky people :p */
2200 } else if (!strcasecmp(v->name, "dontwarn")) {
2201 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2202 /* Dump core in case of crash (-g) */
2203 } else if (!strcasecmp(v->name, "dumpcore")) {
2204 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2205 /* Cache recorded sound files to another directory during recording */
2206 } else if (!strcasecmp(v->name, "cache_record_files")) {
2207 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2208 /* Specify cache directory */
2209 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2210 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2211 /* Build transcode paths via SLINEAR, instead of directly */
2212 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2213 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2214 /* Transmit SLINEAR silence while a channel is being recorded */
2215 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2216 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2217 /* Enable internal timing */
2218 } else if (!strcasecmp(v->name, "internal_timing")) {
2219 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2220 } else if (!strcasecmp(v->name, "maxcalls")) {
2221 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2222 option_maxcalls = 0;
2224 } else if (!strcasecmp(v->name, "maxload")) {
2227 if (getloadavg(test, 1) == -1) {
2228 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2229 option_maxload = 0.0;
2230 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2231 option_maxload = 0.0;
2233 /* What user to run as */
2234 } else if (!strcasecmp(v->name, "runuser")) {
2235 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2236 /* What group to run as */
2237 } else if (!strcasecmp(v->name, "rungroup")) {
2238 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2239 } else if (!strcasecmp(v->name, "systemname")) {
2240 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2244 ast_config_destroy(cfg);
2247 int main(int argc, char *argv[])
2250 char filename[80] = "";
2251 char hostname[MAXHOSTNAMELEN] = "";
2258 int is_child_of_nonroot = 0;
2260 char *runuser = NULL, *rungroup = NULL;
2262 /* Remember original args for restart */
2263 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2264 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2265 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2267 for (x=0; x<argc; x++)
2271 /* if the progname is rasterisk consider it a remote console */
2272 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2273 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2275 if (gethostname(hostname, sizeof(hostname)-1))
2276 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2277 ast_mainpid = getpid();
2281 ast_builtins_init();
2284 /* When Asterisk restarts after it has dropped the root privileges,
2285 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2287 if (getenv("ASTERISK_ALREADY_NONROOT"))
2288 is_child_of_nonroot=1;
2290 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2291 /* Check for options */
2292 while ((c = getopt(argc, argv, "tThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2296 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2299 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2302 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2305 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2308 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2311 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2314 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2318 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2321 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2322 option_maxcalls = 0;
2325 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2326 option_maxload = 0.0;
2329 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2332 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2335 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2338 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2342 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2343 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2346 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2349 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2352 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2371 /* For remote connections, change the name of the remote connection.
2372 * We do this for the benefit of init scripts (which need to know if/when
2373 * the main asterisk process has died yet). */
2374 if (ast_opt_remote) {
2375 strcpy(argv[0], "rasterisk");
2376 for (x = 1; x < argc; x++) {
2377 argv[x] = argv[0] + 10;
2381 if (ast_opt_console && !option_verbose)
2382 ast_verbose("[ Reading Master Configuration ]");
2385 if (ast_opt_dump_core) {
2387 memset(&l, 0, sizeof(l));
2388 l.rlim_cur = RLIM_INFINITY;
2389 l.rlim_max = RLIM_INFINITY;
2390 if (setrlimit(RLIMIT_CORE, &l)) {
2391 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2395 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2396 rungroup = ast_config_AST_RUN_GROUP;
2397 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2398 runuser = ast_config_AST_RUN_USER;
2402 if (!is_child_of_nonroot)
2403 ast_set_priority(ast_opt_high_priority);
2405 if (!is_child_of_nonroot && rungroup) {
2407 gr = getgrnam(rungroup);
2409 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2412 if (setgid(gr->gr_gid)) {
2413 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2416 if (setgroups(0, NULL)) {
2417 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2421 ast_verbose("Running as group '%s'\n", rungroup);
2424 if (!is_child_of_nonroot && runuser) {
2426 pw = getpwnam(runuser);
2428 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2432 if (setgid(pw->pw_gid)) {
2433 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2436 if (initgroups(pw->pw_name, pw->pw_gid)) {
2437 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2441 if (setuid(pw->pw_uid)) {
2442 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2445 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2447 ast_verbose("Running as user '%s'\n", runuser);
2450 #endif /* __CYGWIN__ */
2453 if (geteuid() && ast_opt_dump_core) {
2454 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2455 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2464 if (ast_opt_console && !option_verbose)
2465 ast_verbose("[ Initializing Custom Configuration Options ]");
2466 /* custom config setup */
2467 register_config_cli();
2470 if (ast_opt_console) {
2471 if (el_hist == NULL || el == NULL)
2472 ast_el_initialize();
2474 if (!ast_strlen_zero(filename))
2475 ast_el_read_history(filename);
2478 if (ast_tryconnect()) {
2479 /* One is already running */
2480 if (ast_opt_remote) {
2482 ast_remotecontrol(xarg);
2483 quit_handler(0, 0, 0, 0);
2486 printf(term_quit());
2487 ast_register_verbose(console_verboser);
2489 ast_remotecontrol(NULL);
2490 quit_handler(0, 0, 0, 0);
2493 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2494 printf(term_quit());
2497 } else if (ast_opt_remote || ast_opt_exec) {
2498 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2499 printf(term_quit());
2502 /* Blindly write pid file since we couldn't connect */
2503 unlink(ast_config_AST_PID);
2504 f = fopen(ast_config_AST_PID, "w");
2506 fprintf(f, "%d\n", (int)getpid());
2509 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2511 if (!option_verbose && !option_debug && !ast_opt_no_fork && !ast_opt_console) {
2513 /* Blindly re-write pid file since we are forking */
2514 unlink(ast_config_AST_PID);
2515 f = fopen(ast_config_AST_PID, "w");
2517 fprintf(f, "%d\n", (int)getpid());
2520 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2523 /* Test recursive mutex locking. */
2524 if (test_for_thread_safety())
2525 ast_verbose("Warning! Asterisk is not thread safe.\n");
2529 sigaddset(&sigs, SIGHUP);
2530 sigaddset(&sigs, SIGTERM);
2531 sigaddset(&sigs, SIGINT);
2532 sigaddset(&sigs, SIGPIPE);
2533 sigaddset(&sigs, SIGWINCH);
2534 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2535 if (ast_opt_console || option_verbose || ast_opt_remote)
2536 ast_register_verbose(console_verboser);
2537 /* Print a welcome message if desired */
2538 if (option_verbose || ast_opt_console) {
2541 if (ast_opt_console && !option_verbose)
2542 ast_verbose("[ Booting...");
2544 signal(SIGURG, urg_handler);
2545 signal(SIGINT, __quit_handler);
2546 signal(SIGTERM, __quit_handler);
2547 signal(SIGHUP, hup_handler);
2548 signal(SIGCHLD, child_handler);
2549 signal(SIGPIPE, SIG_IGN);
2551 /* ensure that the random number generators are seeded with a different value every time
2554 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2555 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2557 if (init_logger()) {
2558 printf(term_quit());
2561 if (dnsmgr_init()) {
2562 printf(term_quit());
2565 /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2566 if (load_modules(1)) {
2567 printf(term_quit());
2571 ast_channels_init();
2572 if (init_manager()) {
2573 printf(term_quit());
2576 if (ast_cdr_engine_init()) {
2577 printf(term_quit());
2580 if (ast_device_state_engine_init()) {
2581 printf(term_quit());
2585 #if defined(T38_SUPPORT)
2588 if (ast_image_init()) {
2589 printf(term_quit());
2592 if (ast_file_init()) {
2593 printf(term_quit());
2597 printf(term_quit());
2600 if (load_modules(0)) {
2601 printf(term_quit());
2604 if (init_framer()) {
2605 printf(term_quit());
2609 printf(term_quit());
2612 if (ast_enum_init()) {
2613 printf(term_quit());
2617 dnsmgr_start_refresh();
2620 /* This should no longer be necessary */
2621 /* sync cust config and reload some internals in case a custom config handler binded to them */
2622 read_ast_cust_config();
2629 /* We might have the option of showing a console, but for now just
2631 if (ast_opt_console && !option_verbose)
2632 ast_verbose(" ]\n");
2633 if (option_verbose || ast_opt_console)
2634 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2635 if (ast_opt_no_fork)
2636 consolethread = pthread_self();
2637 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2638 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2639 #ifdef __AST_DEBUG_MALLOC
2642 time(&ast_startuptime);
2643 ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2644 if (ast_opt_console) {
2645 /* Console stuff now... */
2646 /* Register our quit function */
2648 set_icon("Asterisk");
2649 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
2653 buf = (char *)el_gets(el, &num);
2655 if (buf[strlen(buf)-1] == '\n')
2656 buf[strlen(buf)-1] = '\0';
2658 consolehandler((char *)buf);
2660 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2661 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2662 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2664 fd = open("/dev/null", O_RDWR);
2666 dup2(fd, STDOUT_FILENO);
2667 dup2(fd, STDIN_FILENO);
2669 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2677 for(;;) { /* apparently needed for the MACos */
2678 struct pollfd p = { -1 /* no descriptor */, 0, 0 };