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>
84 #include <sys/capability.h>
89 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
92 int daemon(int, int); /* defined in libresolv of all places */
96 #include "asterisk/logger.h"
97 #include "asterisk/options.h"
98 #include "asterisk/cli.h"
99 #include "asterisk/channel.h"
100 #include "asterisk/ulaw.h"
101 #include "asterisk/alaw.h"
102 #include "asterisk/callerid.h"
103 #include "asterisk/image.h"
104 #include "asterisk/tdd.h"
105 #include "asterisk/term.h"
106 #include "asterisk/manager.h"
107 #include "asterisk/cdr.h"
108 #include "asterisk/pbx.h"
109 #include "asterisk/enum.h"
110 #include "asterisk/rtp.h"
111 #include "asterisk/http.h"
112 #include "asterisk/udptl.h"
113 #include "asterisk/app.h"
114 #include "asterisk/lock.h"
115 #include "asterisk/utils.h"
116 #include "asterisk/file.h"
117 #include "asterisk/io.h"
118 #include "asterisk/lock.h"
119 #include "editline/histedit.h"
120 #include "asterisk/config.h"
121 #include "asterisk/version.h"
122 #include "asterisk/linkedlists.h"
123 #include "asterisk/devicestate.h"
125 #include "asterisk/doxyref.h" /* Doxygen documentation */
127 #include "../defaults.h"
130 #define AF_LOCAL AF_UNIX
131 #define PF_LOCAL PF_UNIX
134 #define AST_MAX_CONNECTS 128
137 /*! \brief Welcome message when starting a CLI interface */
138 #define WELCOME_MESSAGE \
139 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
140 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
141 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
142 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
143 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
144 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
145 ast_verbose("=========================================================================\n")
147 /*! \defgroup main_options
148 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
149 the operating system command line when starting Asterisk
150 Some of them can be changed in the CLI
154 extern int ast_language_is_prefix; /* XXX move to some header */
156 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
158 int option_verbose = 0; /*!< Verbosity level */
159 int option_debug = 0; /*!< Debug level */
161 double option_maxload = 0.0; /*!< Max load avg on system */
162 int option_maxcalls = 0; /*!< Max number of active calls */
166 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
167 char debug_filename[AST_FILENAME_MAX] = "";
169 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
170 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
173 int fd; /*!< File descriptor */
174 int p[2]; /*!< Pipe */
175 pthread_t t; /*!< Thread of handler */
176 int mute; /*!< Is the console muted for logs */
181 AST_LIST_ENTRY(ast_atexit) list;
184 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
186 time_t ast_startuptime;
187 time_t ast_lastreloadtime;
189 static History *el_hist = NULL;
190 static EditLine *el = NULL;
191 static char *remotehostname;
193 struct console consoles[AST_MAX_CONNECTS];
195 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
197 static int ast_el_add_history(char *);
198 static int ast_el_read_history(char *);
199 static int ast_el_write_history(char *);
201 char ast_config_AST_CONFIG_DIR[PATH_MAX];
202 char ast_config_AST_CONFIG_FILE[PATH_MAX];
203 char ast_config_AST_MODULE_DIR[PATH_MAX];
204 char ast_config_AST_SPOOL_DIR[PATH_MAX];
205 char ast_config_AST_MONITOR_DIR[PATH_MAX];
206 char ast_config_AST_VAR_DIR[PATH_MAX];
207 char ast_config_AST_DATA_DIR[PATH_MAX];
208 char ast_config_AST_LOG_DIR[PATH_MAX];
209 char ast_config_AST_AGI_DIR[PATH_MAX];
210 char ast_config_AST_DB[PATH_MAX];
211 char ast_config_AST_KEY_DIR[PATH_MAX];
212 char ast_config_AST_PID[PATH_MAX];
213 char ast_config_AST_SOCKET[PATH_MAX];
214 char ast_config_AST_RUN_DIR[PATH_MAX];
215 char ast_config_AST_RUN_USER[PATH_MAX];
216 char ast_config_AST_RUN_GROUP[PATH_MAX];
217 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
218 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
219 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
220 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
221 char ast_config_AST_SYSTEM_NAME[20] = "";
223 extern const char *ast_build_hostname;
224 extern const char *ast_build_kernel;
225 extern const char *ast_build_machine;
226 extern const char *ast_build_os;
227 extern const char *ast_build_date;
228 extern const char *ast_build_user;
230 static char *_argv[256];
231 static int shuttingdown = 0;
232 static int restartnow = 0;
233 static pthread_t consolethread = AST_PTHREADT_NULL;
235 static char randompool[256];
237 #if !defined(LOW_MEMORY)
238 struct file_version {
239 AST_LIST_ENTRY(file_version) list;
244 static AST_LIST_HEAD_STATIC(file_versions, file_version);
246 void ast_register_file_version(const char *file, const char *version)
248 struct file_version *new;
250 size_t version_length;
252 work = ast_strdupa(version);
253 work = ast_strip(ast_strip_quoted(work, "$", "$"));
254 version_length = strlen(work) + 1;
256 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
260 new->version = (char *) new + sizeof(*new);
261 memcpy(new->version, work, version_length);
262 AST_LIST_LOCK(&file_versions);
263 AST_LIST_INSERT_HEAD(&file_versions, new, list);
264 AST_LIST_UNLOCK(&file_versions);
267 void ast_unregister_file_version(const char *file)
269 struct file_version *find;
271 AST_LIST_LOCK(&file_versions);
272 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
273 if (!strcasecmp(find->file, file)) {
274 AST_LIST_REMOVE_CURRENT(&file_versions, list);
278 AST_LIST_TRAVERSE_SAFE_END;
279 AST_LIST_UNLOCK(&file_versions);
284 struct thread_list_t {
285 AST_LIST_ENTRY(thread_list_t) list;
290 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
292 static char show_threads_help[] =
293 "Usage: show threads\n"
294 " List threads currently active in the system.\n";
296 void ast_register_thread(char *name)
298 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
302 new->id = pthread_self();
303 new->name = name; /* this was a copy already */
304 AST_LIST_LOCK(&thread_list);
305 AST_LIST_INSERT_HEAD(&thread_list, new, list);
306 AST_LIST_UNLOCK(&thread_list);
309 void ast_unregister_thread(void *id)
311 struct thread_list_t *x;
313 AST_LIST_LOCK(&thread_list);
314 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
315 if ((void *)x->id == id) {
316 AST_LIST_REMOVE_CURRENT(&thread_list, list);
320 AST_LIST_TRAVERSE_SAFE_END;
321 AST_LIST_UNLOCK(&thread_list);
328 static int handle_show_threads(int fd, int argc, char *argv[])
331 struct thread_list_t *cur;
333 AST_LIST_LOCK(&thread_list);
334 AST_LIST_TRAVERSE(&thread_list, cur, list) {
335 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
338 AST_LIST_UNLOCK(&thread_list);
339 ast_cli(fd, "%d threads listed.\n", count);
343 struct profile_entry {
345 uint64_t scale; /* if non-zero, values are scaled by this */
351 struct profile_data {
354 struct profile_entry e[0];
357 static struct profile_data *prof_data;
359 /*! \brief allocates a counter with a given name and scale.
360 * \return Returns the identifier of the counter.
362 int ast_add_profile(const char *name, uint64_t scale)
364 int l = sizeof(struct profile_data);
365 int n = 10; /* default entries */
367 if (prof_data == NULL) {
368 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
369 if (prof_data == NULL)
371 prof_data->entries = 0;
372 prof_data->max_size = n;
374 if (prof_data->entries >= prof_data->max_size) {
376 n = prof_data->max_size + 20;
377 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
381 prof_data->max_size = n;
383 n = prof_data->entries++;
384 prof_data->e[n].name = ast_strdup(name);
385 prof_data->e[n].value = 0;
386 prof_data->e[n].events = 0;
387 prof_data->e[n].mark = 0;
388 prof_data->e[n].scale = scale;
392 int64_t ast_profile(int i, int64_t delta)
394 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
396 if (prof_data->e[i].scale > 1)
397 delta /= prof_data->e[i].scale;
398 prof_data->e[i].value += delta;
399 prof_data->e[i].events++;
400 return prof_data->e[i].value;
403 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
404 #if defined(__FreeBSD__)
405 #include <machine/cpufunc.h>
407 static __inline uint64_t
412 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
416 #else /* supply a dummy function on other platforms */
417 static __inline uint64_t
424 int64_t ast_mark(int i, int startstop)
426 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
429 prof_data->e[i].mark = rdtsc();
431 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
432 if (prof_data->e[i].scale > 1)
433 prof_data->e[i].mark /= prof_data->e[i].scale;
434 prof_data->e[i].value += prof_data->e[i].mark;
435 prof_data->e[i].events++;
437 return prof_data->e[i].mark;
440 static int handle_show_profile(int fd, int argc, char *argv[])
445 if (prof_data == NULL)
449 max = prof_data->entries;
450 if (argc >= 3) { /* specific entries */
451 if (isdigit(argv[2][0])) {
453 if (argc == 4 && strcmp(argv[3], "-"))
458 if (max > prof_data->entries)
459 max = prof_data->entries;
460 if (!strcmp(argv[1], "clear")) {
461 for (i= min; i < max; i++) {
462 if (!search || strstr(prof_data->e[i].name, search)) {
463 prof_data->e[i].value = 0;
464 prof_data->e[i].events = 0;
469 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
470 prof_data->entries, prof_data->max_size);
471 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
472 "Value", "Average", "Name");
473 for (i = min; i < max; i++) {
474 struct profile_entry *e = &prof_data->e[i];
475 if (!search || strstr(prof_data->e[i].name, search))
476 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
479 (long)e->events, (long long)e->value,
480 (long long)(e->events ? e->value / e->events : e->value),
486 static char show_version_files_help[] =
487 "Usage: file list version [like <pattern>]\n"
488 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
489 " Optional regular expression pattern is used to filter the file list.\n";
491 /*! \brief CLI command to list module versions */
492 static int handle_show_version_files(int fd, int argc, char *argv[])
494 #define FORMAT "%-25.25s %-40.40s\n"
495 struct file_version *iterator;
503 if (!strcasecmp(argv[3], "like")) {
504 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
505 return RESULT_SHOWUSAGE;
508 return RESULT_SHOWUSAGE;
516 return RESULT_SHOWUSAGE;
519 ast_cli(fd, FORMAT, "File", "Revision");
520 ast_cli(fd, FORMAT, "----", "--------");
521 AST_LIST_LOCK(&file_versions);
522 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
523 if (havename && strcasecmp(iterator->file, argv[3]))
526 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
529 ast_cli(fd, FORMAT, iterator->file, iterator->version);
534 AST_LIST_UNLOCK(&file_versions);
536 ast_cli(fd, "%d files listed.\n", count_files);
542 return RESULT_SUCCESS;
546 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
548 struct file_version *find;
551 int matchlen = strlen(word);
556 AST_LIST_LOCK(&file_versions);
557 AST_LIST_TRAVERSE(&file_versions, find, list) {
558 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
559 ret = ast_strdup(find->file);
563 AST_LIST_UNLOCK(&file_versions);
567 #endif /* ! LOW_MEMORY */
569 int ast_register_atexit(void (*func)(void))
572 struct ast_atexit *ae;
573 ast_unregister_atexit(func);
574 AST_LIST_LOCK(&atexits);
575 if ((ae = ast_calloc(1, sizeof(*ae)))) {
576 AST_LIST_INSERT_HEAD(&atexits, ae, list);
580 AST_LIST_UNLOCK(&atexits);
584 void ast_unregister_atexit(void (*func)(void))
586 struct ast_atexit *ae;
587 AST_LIST_LOCK(&atexits);
588 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
589 if (ae->func == func) {
590 AST_LIST_REMOVE_CURRENT(&atexits, list);
594 AST_LIST_TRAVERSE_SAFE_END
595 AST_LIST_UNLOCK(&atexits);
598 static int fdprint(int fd, const char *s)
600 return write(fd, s, strlen(s) + 1);
603 /*! \brief NULL handler so we can collect the child exit status */
604 static void null_sig_handler(int signal)
609 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
610 /*! \brief Keep track of how many threads are currently trying to wait*() on
612 static unsigned int safe_system_level = 0;
613 static void *safe_system_prev_handler;
615 void ast_replace_sigchld(void)
619 ast_mutex_lock(&safe_system_lock);
620 level = safe_system_level++;
622 /* only replace the handler if it has not already been done */
624 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
626 ast_mutex_unlock(&safe_system_lock);
629 void ast_unreplace_sigchld(void)
633 ast_mutex_lock(&safe_system_lock);
634 level = --safe_system_level;
636 /* only restore the handler if we are the last one */
638 signal(SIGCHLD, safe_system_prev_handler);
640 ast_mutex_unlock(&safe_system_lock);
643 int ast_safe_system(const char *s)
648 struct rusage rusage;
651 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
652 ast_replace_sigchld();
654 #ifdef HAVE_WORKING_FORK
661 if (ast_opt_high_priority)
663 /* Close file descriptors and launch system command */
664 for (x = STDERR_FILENO + 1; x < 4096; x++)
666 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
668 } else if (pid > 0) {
670 res = wait4(pid, &status, 0, &rusage);
672 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
674 } else if (errno != EINTR)
678 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
682 ast_unreplace_sigchld();
691 * \brief mute or unmute a console from logging
693 void ast_console_toggle_mute(int fd) {
695 for (x = 0;x < AST_MAX_CONNECTS; x++) {
696 if (fd == consoles[x].fd) {
697 if (consoles[x].mute) {
698 consoles[x].mute = 0;
699 ast_cli(fd, "Console is not muted anymore.\n");
701 consoles[x].mute = 1;
702 ast_cli(fd, "Console is muted.\n");
707 ast_cli(fd, "Couldn't find remote console.\n");
711 * \brief log the string to all attached console clients
713 static void ast_network_puts_mutable(const char *string)
716 for (x = 0;x < AST_MAX_CONNECTS; x++) {
717 if (consoles[x].mute)
719 if (consoles[x].fd > -1)
720 fdprint(consoles[x].p[1], string);
725 * \brief log the string to the console, and all attached
728 void ast_console_puts_mutable(const char *string)
730 fputs(string, stdout);
732 ast_network_puts_mutable(string);
736 * \brief write the string to all attached console clients
738 static void ast_network_puts(const char *string)
741 for (x=0; x < AST_MAX_CONNECTS; x++) {
742 if (consoles[x].fd > -1)
743 fdprint(consoles[x].p[1], string);
748 * write the string to the console, and all attached
751 void ast_console_puts(const char *string)
753 fputs(string, stdout);
755 ast_network_puts(string);
758 static void network_verboser(const char *s)
760 ast_network_puts_mutable(s);
763 static pthread_t lthread;
765 static void *netconsole(void *vconsole)
767 struct console *con = vconsole;
768 char hostname[MAXHOSTNAMELEN] = "";
771 struct pollfd fds[2];
773 if (gethostname(hostname, sizeof(hostname)-1))
774 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
775 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
776 fdprint(con->fd, tmp);
779 fds[0].events = POLLIN;
781 fds[1].fd = con->p[0];
782 fds[1].events = POLLIN;
785 res = poll(fds, 2, -1);
788 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
791 if (fds[0].revents) {
792 res = read(con->fd, tmp, sizeof(tmp));
797 ast_cli_command(con->fd, tmp);
799 if (fds[1].revents) {
800 res = read(con->p[0], tmp, sizeof(tmp));
802 ast_log(LOG_ERROR, "read returned %d\n", res);
805 res = write(con->fd, tmp, res);
810 if (option_verbose > 2)
811 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
820 static void *listener(void *unused)
822 struct sockaddr_un sunaddr;
827 struct pollfd fds[1];
829 pthread_attr_init(&attr);
830 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
834 fds[0].fd = ast_socket;
835 fds[0].events = POLLIN;
836 s = poll(fds, 1, -1);
837 pthread_testcancel();
840 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
843 len = sizeof(sunaddr);
844 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
847 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
849 for (x = 0; x < AST_MAX_CONNECTS; x++) {
850 if (consoles[x].fd < 0) {
851 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
852 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
854 fdprint(s, "Server failed to create pipe\n");
858 flags = fcntl(consoles[x].p[1], F_GETFL);
859 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
861 consoles[x].mute = ast_opt_mute;
862 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
863 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
864 close(consoles[x].p[0]);
865 close(consoles[x].p[1]);
867 fdprint(s, "Server failed to spawn thread\n");
873 if (x >= AST_MAX_CONNECTS) {
874 fdprint(s, "No more connections allowed\n");
875 ast_log(LOG_WARNING, "No more connections allowed\n");
877 } else if (consoles[x].fd > -1) {
878 if (option_verbose > 2)
879 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
886 static int ast_makesocket(void)
888 struct sockaddr_un sunaddr;
894 for (x = 0; x < AST_MAX_CONNECTS; x++)
896 unlink(ast_config_AST_SOCKET);
897 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
898 if (ast_socket < 0) {
899 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
902 memset(&sunaddr, 0, sizeof(sunaddr));
903 sunaddr.sun_family = AF_LOCAL;
904 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
905 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
907 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
912 res = listen(ast_socket, 2);
914 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
919 ast_register_verbose(network_verboser);
920 ast_pthread_create(<hread, NULL, listener, NULL);
922 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
924 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
925 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
931 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
933 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
934 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
940 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
941 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
943 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
946 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
948 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
949 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
955 static int ast_tryconnect(void)
957 struct sockaddr_un sunaddr;
959 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
960 if (ast_consock < 0) {
961 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
964 memset(&sunaddr, 0, sizeof(sunaddr));
965 sunaddr.sun_family = AF_LOCAL;
966 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
967 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
976 /*! \brief Urgent handler
978 Called by soft_hangup to interrupt the poll, read, or other
979 system call. We don't actually need to do anything though.
980 Remember: Cannot EVER ast_log from within a signal handler
982 static void urg_handler(int num)
984 signal(num, urg_handler);
988 static void hup_handler(int num)
990 if (option_verbose > 1)
991 printf("Received HUP signal -- Reloading configs\n");
993 execvp(_argv[0], _argv);
994 /* XXX This could deadlock XXX */
995 ast_module_reload(NULL);
996 signal(num, hup_handler);
999 static void child_handler(int sig)
1001 /* Must not ever ast_log or ast_verbose within signal handler */
1005 * Reap all dead children -- not just one
1007 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1009 if (n == 0 && option_debug)
1010 printf("Huh? Child handler, but nobody there?\n");
1011 signal(sig, child_handler);
1014 /*! \brief Set an X-term or screen title */
1015 static void set_title(char *text)
1017 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1018 fprintf(stdout, "\033]2;%s\007", text);
1021 static void set_icon(char *text)
1023 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1024 fprintf(stdout, "\033]1;%s\007", text);
1027 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1028 else. If your PBX has heavy activity on it, this is a good thing. */
1029 int ast_set_priority(int pri)
1031 struct sched_param sched;
1032 memset(&sched, 0, sizeof(sched));
1035 sched.sched_priority = 10;
1036 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1037 ast_log(LOG_WARNING, "Unable to set high priority\n");
1041 ast_verbose("Set to realtime thread\n");
1043 sched.sched_priority = 0;
1044 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
1045 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1051 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1052 ast_log(LOG_WARNING, "Unable to set high priority\n");
1056 ast_verbose("Set to high priority\n");
1058 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1059 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1067 static void ast_run_atexits(void)
1069 struct ast_atexit *ae;
1070 AST_LIST_LOCK(&atexits);
1071 AST_LIST_TRAVERSE(&atexits, ae, list) {
1075 AST_LIST_UNLOCK(&atexits);
1078 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1080 char filename[80] = "";
1083 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1084 ast_cdr_engine_term();
1088 /* Begin shutdown routine, hanging up active channels */
1089 ast_begin_shutdown(1);
1090 if (option_verbose && ast_opt_console)
1091 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1095 /* Wait up to 15 seconds for all channels to go away */
1098 if (!ast_active_channels())
1102 /* Sleep 1/10 of a second */
1107 ast_begin_shutdown(0);
1108 if (option_verbose && ast_opt_console)
1109 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1111 if (!ast_active_channels())
1119 if (!shuttingdown) {
1120 if (option_verbose && ast_opt_console)
1121 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1125 if (ast_opt_console || ast_opt_remote) {
1127 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1128 if (!ast_strlen_zero(filename))
1129 ast_el_write_history(filename);
1132 if (el_hist != NULL)
1133 history_end(el_hist);
1136 ast_verbose("Executing last minute cleanups\n");
1138 /* Called on exit */
1139 if (option_verbose && ast_opt_console)
1140 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1142 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1143 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1144 if (ast_socket > -1) {
1145 pthread_cancel(lthread);
1148 unlink(ast_config_AST_SOCKET);
1150 if (ast_consock > -1)
1152 if (!ast_opt_remote)
1153 unlink(ast_config_AST_PID);
1154 printf(term_quit());
1156 if (option_verbose || ast_opt_console)
1157 ast_verbose("Preparing for Asterisk restart...\n");
1158 /* Mark all FD's for closing on exec */
1159 for (x=3; x < 32768; x++) {
1160 fcntl(x, F_SETFD, FD_CLOEXEC);
1162 if (option_verbose || ast_opt_console)
1163 ast_verbose("Restarting Asterisk NOW...\n");
1169 /* If there is a consolethread running send it a SIGHUP
1170 so it can execvp, otherwise we can do it ourselves */
1171 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1172 pthread_kill(consolethread, SIGHUP);
1173 /* Give the signal handler some time to complete */
1176 execvp(_argv[0], _argv);
1185 static void __quit_handler(int num)
1187 quit_handler(num, 0, 1, 0);
1190 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1193 if (!strncmp(s, cmp, strlen(cmp))) {
1194 c = s + strlen(cmp);
1195 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1201 static void console_verboser(const char *s)
1204 const char *c = NULL;
1206 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1207 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1208 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1209 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1217 /* Wake up a poll()ing console */
1218 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1219 pthread_kill(consolethread, SIGURG);
1222 static int ast_all_zeros(char *s)
1232 static void consolehandler(char *s)
1237 /* Called when readline data is available */
1238 if (!ast_all_zeros(s))
1239 ast_el_add_history(s);
1240 /* The real handler for bang */
1243 ast_safe_system(s+1);
1245 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1247 ast_cli_command(STDOUT_FILENO, s);
1250 static int remoteconsolehandler(char *s)
1254 /* Called when readline data is available */
1255 if (!ast_all_zeros(s))
1256 ast_el_add_history(s);
1257 /* The real handler for bang */
1260 ast_safe_system(s+1);
1262 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1265 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1266 (s[4] == '\0' || isspace(s[4]))) {
1267 quit_handler(0, 0, 0, 0);
1274 static char abort_halt_help[] =
1275 "Usage: abort shutdown\n"
1276 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1277 " call operations.\n";
1279 static char shutdown_now_help[] =
1281 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1283 static char shutdown_gracefully_help[] =
1284 "Usage: stop gracefully\n"
1285 " Causes Asterisk to not accept new calls, and exit when all\n"
1286 " active calls have terminated normally.\n";
1288 static char shutdown_when_convenient_help[] =
1289 "Usage: stop when convenient\n"
1290 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1292 static char restart_now_help[] =
1293 "Usage: restart now\n"
1294 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1297 static char restart_gracefully_help[] =
1298 "Usage: restart gracefully\n"
1299 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1300 " restart when all active calls have ended.\n";
1302 static char restart_when_convenient_help[] =
1303 "Usage: restart when convenient\n"
1304 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1306 static char bang_help[] =
1307 "Usage: !<command>\n"
1308 " Executes a given shell command\n";
1310 static char show_warranty_help[] =
1311 "Usage: show warranty\n"
1312 " Shows the warranty (if any) for this copy of Asterisk.\n";
1314 static char show_license_help[] =
1315 "Usage: show license\n"
1316 " Shows the license(s) for this copy of Asterisk.\n";
1318 static char version_help[] =
1319 "Usage: show version\n"
1320 " Shows Asterisk version information.\n";
1322 static int handle_version(int fd, int argc, char *argv[])
1325 return RESULT_SHOWUSAGE;
1326 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1327 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1328 ast_build_machine, ast_build_os, ast_build_date);
1329 return RESULT_SUCCESS;
1333 static int handle_quit(int fd, int argc, char *argv[])
1336 return RESULT_SHOWUSAGE;
1337 quit_handler(0, 0, 1, 0);
1338 return RESULT_SUCCESS;
1342 static int handle_shutdown_now(int fd, int argc, char *argv[])
1345 return RESULT_SHOWUSAGE;
1346 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1347 return RESULT_SUCCESS;
1350 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1353 return RESULT_SHOWUSAGE;
1354 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1355 return RESULT_SUCCESS;
1358 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1361 return RESULT_SHOWUSAGE;
1362 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1363 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1364 return RESULT_SUCCESS;
1367 static int handle_restart_now(int fd, int argc, char *argv[])
1370 return RESULT_SHOWUSAGE;
1371 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1372 return RESULT_SUCCESS;
1375 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1378 return RESULT_SHOWUSAGE;
1379 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1380 return RESULT_SUCCESS;
1383 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1386 return RESULT_SHOWUSAGE;
1387 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1388 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1389 return RESULT_SUCCESS;
1392 static int handle_abort_halt(int fd, int argc, char *argv[])
1395 return RESULT_SHOWUSAGE;
1396 ast_cancel_shutdown();
1398 return RESULT_SUCCESS;
1401 static int handle_bang(int fd, int argc, char *argv[])
1403 return RESULT_SUCCESS;
1405 static const char *warranty_lines[] = {
1409 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1410 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1411 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1412 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1413 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1414 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1415 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1416 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1417 "REPAIR OR CORRECTION.\n",
1419 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1420 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1421 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1422 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1423 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1424 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1425 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1426 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1427 "POSSIBILITY OF SUCH DAMAGES.\n",
1430 static int show_warranty(int fd, int argc, char *argv[])
1434 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1435 ast_cli(fd, (char *) warranty_lines[x]);
1437 return RESULT_SUCCESS;
1440 static const char *license_lines[] = {
1442 "This program is free software; you can redistribute it and/or modify\n",
1443 "it under the terms of the GNU General Public License version 2 as\n",
1444 "published by the Free Software Foundation.\n",
1446 "This program also contains components licensed under other licenses.\n",
1449 "This program is distributed in the hope that it will be useful,\n",
1450 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1451 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1452 "GNU General Public License for more details.\n",
1454 "You should have received a copy of the GNU General Public License\n",
1455 "along with this program; if not, write to the Free Software\n",
1456 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1459 static int show_license(int fd, int argc, char *argv[])
1463 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1464 ast_cli(fd, (char *) license_lines[x]);
1466 return RESULT_SUCCESS;
1469 #define ASTERISK_PROMPT "*CLI> "
1471 #define ASTERISK_PROMPT2 "%s*CLI> "
1473 static struct ast_cli_entry cli_asterisk[] = {
1474 { { "abort", "halt", NULL },
1475 handle_abort_halt, "Cancel a running halt",
1478 { { "stop", "now", NULL },
1479 handle_shutdown_now, "Shut down Asterisk immediately",
1480 shutdown_now_help },
1482 { { "stop", "gracefully", NULL },
1483 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1484 shutdown_gracefully_help },
1486 { { "stop", "when", "convenient", NULL },
1487 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1488 shutdown_when_convenient_help },
1490 { { "restart", "now", NULL },
1491 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1493 { { "restart", "gracefully", NULL },
1494 handle_restart_gracefully, "Restart Asterisk gracefully",
1495 restart_gracefully_help },
1497 { { "restart", "when", "convenient", NULL },
1498 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1499 restart_when_convenient_help },
1501 { { "show", "warranty", NULL },
1502 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1503 show_warranty_help },
1505 { { "show", "license", NULL },
1506 show_license, "Show the license(s) for this copy of Asterisk",
1507 show_license_help },
1509 { { "show", "version", NULL },
1510 handle_version, "Display version info",
1514 handle_bang, "Execute a shell command",
1517 #if !defined(LOW_MEMORY)
1518 { { "file", "list", "version", NULL },
1519 handle_show_version_files, "List versions of files used to build Asterisk",
1520 show_version_files_help, complete_show_version_files },
1522 { { "show", "threads", NULL },
1523 handle_show_threads, "Show running threads",
1524 show_threads_help },
1526 { { "profile", "list", NULL },
1527 handle_show_profile, "Display profiling info",
1530 { { "profile", "clear", NULL },
1531 handle_show_profile, "Clear profiling info",
1533 #endif /* ! LOW_MEMORY */
1536 static int ast_el_read_char(EditLine *el, char *cp)
1540 struct pollfd fds[2];
1547 fds[0].fd = ast_consock;
1548 fds[0].events = POLLIN;
1549 if (!ast_opt_exec) {
1550 fds[1].fd = STDIN_FILENO;
1551 fds[1].events = POLLIN;
1554 res = poll(fds, max, -1);
1558 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1562 if (!ast_opt_exec && fds[1].revents) {
1563 num_read = read(STDIN_FILENO, cp, 1);
1569 if (fds[0].revents) {
1570 res = read(ast_consock, buf, sizeof(buf) - 1);
1571 /* if the remote side disappears exit */
1573 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1574 if (!ast_opt_reconnect) {
1575 quit_handler(0, 0, 0, 0);
1578 int reconnects_per_second = 20;
1579 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1580 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1581 if (ast_tryconnect()) {
1582 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1583 printf(term_quit());
1587 usleep(1000000 / reconnects_per_second);
1590 if (tries >= 30 * reconnects_per_second) {
1591 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1592 quit_handler(0, 0, 0, 0);
1599 if (!ast_opt_exec && !lastpos)
1600 write(STDOUT_FILENO, "\r", 1);
1601 write(STDOUT_FILENO, buf, res);
1602 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1615 static char *cli_prompt(EditLine *el)
1617 static char prompt[200];
1622 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1623 char *t = pfmt, *p = prompt;
1624 memset(prompt, 0, sizeof(prompt));
1625 while (*t != '\0' && *p < sizeof(prompt)) {
1627 char hostname[MAXHOSTNAMELEN]="";
1634 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1638 case 'C': /* color */
1640 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1641 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1643 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1644 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1648 /* If the color has been reset correctly, then there's no need to reset it later */
1649 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1655 case 'd': /* date */
1656 memset(&tm, 0, sizeof(tm));
1658 if (localtime_r(&ts, &tm)) {
1659 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1662 case 'h': /* hostname */
1663 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1664 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1666 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1669 case 'H': /* short hostname */
1670 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1671 for (i = 0; i < sizeof(hostname); i++) {
1672 if (hostname[i] == '.') {
1677 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1679 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1683 case 'l': /* load avg */
1685 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1686 float avg1, avg2, avg3;
1687 int actproc, totproc, npid, which;
1688 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1689 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1690 if (sscanf(t, "%d", &which) == 1) {
1693 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1696 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1699 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1702 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1705 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1712 case 's': /* Asterisk system name (from asterisk.conf) */
1713 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1715 case 't': /* time */
1716 memset(&tm, 0, sizeof(tm));
1718 if (localtime_r(&ts, &tm)) {
1719 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1722 case '#': /* process console or remote? */
1723 if (!ast_opt_remote) {
1724 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1726 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1729 case '%': /* literal % */
1730 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1732 case '\0': /* % is last character - prevent bug */
1736 while (*p != '\0') {
1747 /* Force colors back to normal at end */
1748 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1749 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1750 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1752 strncat(p, term_code, sizeof(term_code));
1755 } else if (remotehostname)
1756 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1758 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1763 static char **ast_el_strtoarr(char *buf)
1765 char **match_list = NULL, *retstr;
1766 size_t match_list_len;
1770 while ( (retstr = strsep(&buf, " ")) != NULL) {
1772 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1774 if (matches + 1 >= match_list_len) {
1775 match_list_len <<= 1;
1776 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1777 /* TODO: Handle memory allocation failure */
1781 match_list[matches++] = strdup(retstr);
1785 return (char **) NULL;
1787 if (matches >= match_list_len) {
1788 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1789 /* TODO: Handle memory allocation failure */
1793 match_list[matches] = (char *) NULL;
1798 static int ast_el_sort_compare(const void *i1, const void *i2)
1802 s1 = ((char **)i1)[0];
1803 s2 = ((char **)i2)[0];
1805 return strcasecmp(s1, s2);
1808 static int ast_cli_display_match_list(char **matches, int len, int max)
1810 int i, idx, limit, count;
1811 int screenwidth = 0;
1812 int numoutput = 0, numoutputline = 0;
1814 screenwidth = ast_get_termcols(STDOUT_FILENO);
1816 /* find out how many entries can be put on one line, with two spaces between strings */
1817 limit = screenwidth / (max + 2);
1821 /* how many lines of output */
1822 count = len / limit;
1823 if (count * limit < len)
1828 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1830 for (; count > 0; count--) {
1832 for (i=0; i < limit && matches[idx]; i++, idx++) {
1834 /* Don't print dupes */
1835 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1838 matches[idx] = NULL;
1844 fprintf(stdout, "%-*s ", max, matches[idx]);
1846 matches[idx] = NULL;
1848 if (numoutputline > 0)
1849 fprintf(stdout, "\n");
1856 static char *cli_complete(EditLine *el, int ch)
1862 int retval = CC_ERROR;
1866 LineInfo *lf = (LineInfo *)el_line(el);
1868 *(char *)lf->cursor = '\0';
1869 ptr = (char *)lf->cursor;
1871 while (ptr > lf->buffer) {
1872 if (isspace(*ptr)) {
1880 len = lf->cursor - ptr;
1882 if (ast_opt_remote) {
1883 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1884 fdprint(ast_consock, buf);
1885 res = read(ast_consock, buf, sizeof(buf));
1887 nummatches = atoi(buf);
1889 if (nummatches > 0) {
1891 int mlen = 0, maxmbuf = 2048;
1892 /* Start with a 2048 byte buffer */
1893 if (!(mbuf = ast_malloc(maxmbuf)))
1894 return (char *)(CC_ERROR);
1895 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1896 fdprint(ast_consock, buf);
1899 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1900 if (mlen + 1024 > maxmbuf) {
1901 /* Every step increment buffer 1024 bytes */
1903 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1904 return (char *)(CC_ERROR);
1906 /* Only read 1024 bytes at a time */
1907 res = read(ast_consock, mbuf + mlen, 1024);
1913 matches = ast_el_strtoarr(mbuf);
1916 matches = (char **) NULL;
1918 char **p, *oldbuf=NULL;
1920 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1921 for (p = matches; p && *p; p++) {
1922 if (!oldbuf || strcmp(*p,oldbuf))
1930 int matches_num, maxlen, match_len;
1932 if (matches[0][0] != '\0') {
1933 el_deletestr(el, (int) len);
1934 el_insertstr(el, matches[0]);
1935 retval = CC_REFRESH;
1938 if (nummatches == 1) {
1939 /* Found an exact match */
1940 el_insertstr(el, " ");
1941 retval = CC_REFRESH;
1943 /* Must be more than one match */
1944 for (i=1, maxlen=0; matches[i]; i++) {
1945 match_len = strlen(matches[i]);
1946 if (match_len > maxlen)
1949 matches_num = i - 1;
1950 if (matches_num >1) {
1951 fprintf(stdout, "\n");
1952 ast_cli_display_match_list(matches, nummatches, maxlen);
1953 retval = CC_REDISPLAY;
1955 el_insertstr(el," ");
1956 retval = CC_REFRESH;
1962 return (char *)(long)retval;
1965 static int ast_el_initialize(void)
1968 char *editor = getenv("AST_EDITOR");
1972 if (el_hist != NULL)
1973 history_end(el_hist);
1975 el = el_init("asterisk", stdin, stdout, stderr);
1976 el_set(el, EL_PROMPT, cli_prompt);
1978 el_set(el, EL_EDITMODE, 1);
1979 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1980 el_hist = history_init();
1981 if (!el || !el_hist)
1984 /* setup history with 100 entries */
1985 history(el_hist, &ev, H_SETSIZE, 100);
1987 el_set(el, EL_HIST, history, el_hist);
1989 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1990 /* Bind <tab> to command completion */
1991 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1992 /* Bind ? to command completion */
1993 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1994 /* Bind ^D to redisplay */
1995 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2000 static int ast_el_add_history(char *buf)
2004 if (el_hist == NULL || el == NULL)
2005 ast_el_initialize();
2006 if (strlen(buf) > 256)
2008 return (history(el_hist, &ev, H_ENTER, buf));
2011 static int ast_el_write_history(char *filename)
2015 if (el_hist == NULL || el == NULL)
2016 ast_el_initialize();
2018 return (history(el_hist, &ev, H_SAVE, filename));
2021 static int ast_el_read_history(char *filename)
2027 if (el_hist == NULL || el == NULL)
2028 ast_el_initialize();
2030 if ((f = fopen(filename, "r")) == NULL)
2034 fgets(buf, sizeof(buf), f);
2035 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2037 if (ast_all_zeros(buf))
2039 if ((ret = ast_el_add_history(buf)) == -1)
2047 static void ast_remotecontrol(char * data)
2051 char filename[80] = "";
2057 char *stringp = NULL;
2062 read(ast_consock, buf, sizeof(buf));
2064 write(ast_consock, data, strlen(data) + 1);
2066 hostname = strsep(&stringp, "/");
2067 cpid = strsep(&stringp, "/");
2068 version = strsep(&stringp, "\n");
2070 version = "<Version Unknown>";
2072 strsep(&stringp, ".");
2077 snprintf(tmp, sizeof(tmp), "core verbose %d", option_verbose);
2078 fdprint(ast_consock, tmp);
2079 snprintf(tmp, sizeof(tmp), "core debug %d", option_debug);
2080 fdprint(ast_consock, tmp);
2082 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2083 fdprint(ast_consock, tmp);
2085 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2086 remotehostname = hostname;
2088 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2089 if (el_hist == NULL || el == NULL)
2090 ast_el_initialize();
2092 el_set(el, EL_GETCFN, ast_el_read_char);
2094 if (!ast_strlen_zero(filename))
2095 ast_el_read_history(filename);
2097 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2100 fds.fd = ast_consock;
2101 fds.events = POLLIN;
2103 while (poll(&fds, 1, 100) > 0)
2104 ast_el_read_char(el, &tempchar);
2108 ebuf = (char *)el_gets(el, &num);
2110 if (!ast_strlen_zero(ebuf)) {
2111 if (ebuf[strlen(ebuf)-1] == '\n')
2112 ebuf[strlen(ebuf)-1] = '\0';
2113 if (!remoteconsolehandler(ebuf)) {
2114 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2116 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2122 printf("\nDisconnected from Asterisk server\n");
2125 static int show_version(void)
2127 printf("Asterisk " ASTERISK_VERSION "\n");
2131 static int show_cli_help(void) {
2132 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2133 printf("Usage: asterisk [OPTIONS]\n");
2134 printf("Valid Options:\n");
2135 printf(" -V Display version number and exit\n");
2136 printf(" -C <configfile> Use an alternate configuration file\n");
2137 printf(" -G <group> Run as a group other than the caller\n");
2138 printf(" -U <user> Run as a user other than the caller\n");
2139 printf(" -c Provide console CLI\n");
2140 printf(" -d Enable extra debugging\n");
2141 #if HAVE_WORKING_FORK
2142 printf(" -f Do not fork\n");
2143 printf(" -F Always fork\n");
2145 printf(" -g Dump core in case of a crash\n");
2146 printf(" -h This help screen\n");
2147 printf(" -i Initialize crypto keys at startup\n");
2148 printf(" -I Enable internal timing if Zaptel timer is available\n");
2149 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2150 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2151 printf(" -m Mute the console from debugging and verbose output\n");
2152 printf(" -n Disable console colorization\n");
2153 printf(" -p Run as pseudo-realtime thread\n");
2154 printf(" -q Quiet mode (suppress output)\n");
2155 printf(" -r Connect to Asterisk on this machine\n");
2156 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2157 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2158 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2159 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2160 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2165 static void ast_readconfig(void)
2167 struct ast_config *cfg;
2168 struct ast_variable *v;
2169 char *config = AST_CONFIG_FILE;
2171 if (ast_opt_override_config) {
2172 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2174 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2176 cfg = ast_config_load(config);
2179 /* init with buildtime config */
2180 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2181 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2182 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2183 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2184 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2185 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2186 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2187 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2188 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2189 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2190 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2191 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2192 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2194 /* no asterisk.conf? no problem, use buildtime config! */
2199 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2200 if (!strcasecmp(v->name, "astctlpermissions")) {
2201 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2202 } else if (!strcasecmp(v->name, "astctlowner")) {
2203 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2204 } else if (!strcasecmp(v->name, "astctlgroup")) {
2205 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2206 } else if (!strcasecmp(v->name, "astctl")) {
2207 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2211 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2212 if (!strcasecmp(v->name, "astetcdir")) {
2213 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2214 } else if (!strcasecmp(v->name, "astspooldir")) {
2215 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2216 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2217 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2218 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2219 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2220 } else if (!strcasecmp(v->name, "astdatadir")) {
2221 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2222 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2223 } else if (!strcasecmp(v->name, "astlogdir")) {
2224 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2225 } else if (!strcasecmp(v->name, "astagidir")) {
2226 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2227 } else if (!strcasecmp(v->name, "astrundir")) {
2228 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2229 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2230 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2231 } else if (!strcasecmp(v->name, "astmoddir")) {
2232 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2236 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2237 /* verbose level (-v at startup) */
2238 if (!strcasecmp(v->name, "verbose")) {
2239 option_verbose = atoi(v->value);
2240 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2241 } else if (!strcasecmp(v->name, "timestamp")) {
2242 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2243 /* whether or not to support #exec in config files */
2244 } else if (!strcasecmp(v->name, "execincludes")) {
2245 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2246 /* debug level (-d at startup) */
2247 } else if (!strcasecmp(v->name, "debug")) {
2249 if (sscanf(v->value, "%d", &option_debug) != 1) {
2250 option_debug = ast_true(v->value);
2252 #if HAVE_WORKING_FORK
2253 /* Disable forking (-f at startup) */
2254 } else if (!strcasecmp(v->name, "nofork")) {
2255 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2256 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2257 } else if (!strcasecmp(v->name, "alwaysfork")) {
2258 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2260 /* Run quietly (-q at startup ) */
2261 } else if (!strcasecmp(v->name, "quiet")) {
2262 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2263 /* Run as console (-c at startup, implies nofork) */
2264 } else if (!strcasecmp(v->name, "console")) {
2265 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2266 /* Run with high priority if the O/S permits (-p at startup) */
2267 } else if (!strcasecmp(v->name, "highpriority")) {
2268 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2269 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2270 } else if (!strcasecmp(v->name, "initcrypto")) {
2271 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2272 /* Disable ANSI colors for console (-c at startup) */
2273 } else if (!strcasecmp(v->name, "nocolor")) {
2274 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2275 /* Disable some usage warnings for picky people :p */
2276 } else if (!strcasecmp(v->name, "dontwarn")) {
2277 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2278 /* Dump core in case of crash (-g) */
2279 } else if (!strcasecmp(v->name, "dumpcore")) {
2280 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2281 /* Cache recorded sound files to another directory during recording */
2282 } else if (!strcasecmp(v->name, "cache_record_files")) {
2283 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2284 /* Specify cache directory */
2285 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2286 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2287 /* Build transcode paths via SLINEAR, instead of directly */
2288 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2289 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2290 /* Transmit SLINEAR silence while a channel is being recorded */
2291 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2292 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2293 /* Enable internal timing */
2294 } else if (!strcasecmp(v->name, "internal_timing")) {
2295 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2296 } else if (!strcasecmp(v->name, "maxcalls")) {
2297 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2298 option_maxcalls = 0;
2300 } else if (!strcasecmp(v->name, "maxload")) {
2303 if (getloadavg(test, 1) == -1) {
2304 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2305 option_maxload = 0.0;
2306 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2307 option_maxload = 0.0;
2309 /* What user to run as */
2310 } else if (!strcasecmp(v->name, "runuser")) {
2311 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2312 /* What group to run as */
2313 } else if (!strcasecmp(v->name, "rungroup")) {
2314 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2315 } else if (!strcasecmp(v->name, "systemname")) {
2316 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2317 } else if (!strcasecmp(v->name, "languageprefix")) {
2318 ast_language_is_prefix = ast_true(v->value);
2321 ast_config_destroy(cfg);
2324 int main(int argc, char *argv[])
2327 char filename[80] = "";
2328 char hostname[MAXHOSTNAMELEN] = "";
2335 int is_child_of_nonroot = 0;
2337 char *runuser = NULL, *rungroup = NULL;
2339 /* Remember original args for restart */
2340 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2341 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2342 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2344 for (x=0; x<argc; x++)
2348 /* if the progname is rasterisk consider it a remote console */
2349 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2350 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2352 if (gethostname(hostname, sizeof(hostname)-1))
2353 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2354 ast_mainpid = getpid();
2358 ast_builtins_init();
2361 /* When Asterisk restarts after it has dropped the root privileges,
2362 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2364 if (getenv("ASTERISK_ALREADY_NONROOT"))
2365 is_child_of_nonroot=1;
2367 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2368 /* Check for options */
2369 while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2371 #if HAVE_WORKING_FORK
2373 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2376 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2381 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2384 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2387 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2390 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2393 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2396 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2400 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2403 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2406 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2407 option_maxcalls = 0;
2410 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2411 option_maxload = 0.0;
2414 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2417 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2420 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2423 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2427 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2428 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2431 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2434 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2437 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2456 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2457 ast_register_verbose(console_verboser);
2461 if (ast_opt_console && !option_verbose)
2462 ast_verbose("[ Booting...\n");
2464 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2465 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2466 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2469 /* For remote connections, change the name of the remote connection.
2470 * We do this for the benefit of init scripts (which need to know if/when
2471 * the main asterisk process has died yet). */
2472 if (ast_opt_remote) {
2473 strcpy(argv[0], "rasterisk");
2474 for (x = 1; x < argc; x++) {
2475 argv[x] = argv[0] + 10;
2479 if (ast_opt_console && !option_verbose)
2480 ast_verbose("[ Reading Master Configuration ]\n");
2483 if (ast_opt_dump_core) {
2485 memset(&l, 0, sizeof(l));
2486 l.rlim_cur = RLIM_INFINITY;
2487 l.rlim_max = RLIM_INFINITY;
2488 if (setrlimit(RLIMIT_CORE, &l)) {
2489 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2493 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2494 rungroup = ast_config_AST_RUN_GROUP;
2495 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2496 runuser = ast_config_AST_RUN_USER;
2500 if (!is_child_of_nonroot)
2501 ast_set_priority(ast_opt_high_priority);
2503 if (!is_child_of_nonroot && rungroup) {
2505 gr = getgrnam(rungroup);
2507 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2510 if (setgid(gr->gr_gid)) {
2511 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2514 if (setgroups(0, NULL)) {
2515 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2519 ast_verbose("Running as group '%s'\n", rungroup);
2522 if (!is_child_of_nonroot && runuser) {
2526 #endif /* HAVE_CAP */
2528 pw = getpwnam(runuser);
2530 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2534 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
2535 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
2538 #endif /* HAVE_CAP */
2540 if (setgid(pw->pw_gid)) {
2541 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2544 if (initgroups(pw->pw_name, pw->pw_gid)) {
2545 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2549 if (setuid(pw->pw_uid)) {
2550 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2553 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2555 ast_verbose("Running as user '%s'\n", runuser);
2558 cap = cap_from_text("cap_net_admin=ep");
2559 if (cap_set_proc(cap)) {
2560 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
2563 if (cap_free(cap)) {
2564 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
2567 #endif /* HAVE_CAP */
2570 #endif /* __CYGWIN__ */
2573 if (geteuid() && ast_opt_dump_core) {
2574 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2575 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2584 if (ast_opt_console && !option_verbose)
2585 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2586 /* custom config setup */
2587 register_config_cli();
2590 if (ast_opt_console) {
2591 if (el_hist == NULL || el == NULL)
2592 ast_el_initialize();
2594 if (!ast_strlen_zero(filename))
2595 ast_el_read_history(filename);
2598 if (ast_tryconnect()) {
2599 /* One is already running */
2600 if (ast_opt_remote) {
2602 ast_remotecontrol(xarg);
2603 quit_handler(0, 0, 0, 0);
2606 printf(term_quit());
2607 ast_remotecontrol(NULL);
2608 quit_handler(0, 0, 0, 0);
2611 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2612 printf(term_quit());
2615 } else if (ast_opt_remote || ast_opt_exec) {
2616 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2617 printf(term_quit());
2620 /* Blindly write pid file since we couldn't connect */
2621 unlink(ast_config_AST_PID);
2622 f = fopen(ast_config_AST_PID, "w");
2624 fprintf(f, "%ld\n", (long)getpid());
2627 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2629 #if HAVE_WORKING_FORK
2630 if (ast_opt_always_fork || !ast_opt_no_fork) {
2632 ast_mainpid = getpid();
2633 /* Blindly re-write pid file since we are forking */
2634 unlink(ast_config_AST_PID);
2635 f = fopen(ast_config_AST_PID, "w");
2637 fprintf(f, "%ld\n", (long)ast_mainpid);
2640 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2644 /* Test recursive mutex locking. */
2645 if (test_for_thread_safety())
2646 ast_verbose("Warning! Asterisk is not thread safe.\n");
2650 sigaddset(&sigs, SIGHUP);
2651 sigaddset(&sigs, SIGTERM);
2652 sigaddset(&sigs, SIGINT);
2653 sigaddset(&sigs, SIGPIPE);
2654 sigaddset(&sigs, SIGWINCH);
2655 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2656 signal(SIGURG, urg_handler);
2657 signal(SIGINT, __quit_handler);
2658 signal(SIGTERM, __quit_handler);
2659 signal(SIGHUP, hup_handler);
2660 signal(SIGCHLD, child_handler);
2661 signal(SIGPIPE, SIG_IGN);
2663 /* ensure that the random number generators are seeded with a different value every time
2666 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2667 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2669 if (init_logger()) {
2670 printf(term_quit());
2673 if (load_modules(1)) {
2674 printf(term_quit());
2678 if (dnsmgr_init()) {
2679 printf(term_quit());
2685 ast_channels_init();
2687 if (init_manager()) {
2688 printf(term_quit());
2692 if (ast_cdr_engine_init()) {
2693 printf(term_quit());
2697 if (ast_device_state_engine_init()) {
2698 printf(term_quit());
2706 if (ast_image_init()) {
2707 printf(term_quit());
2711 if (ast_file_init()) {
2712 printf(term_quit());
2717 printf(term_quit());
2721 if (init_framer()) {
2722 printf(term_quit());
2727 printf(term_quit());
2731 if (ast_enum_init()) {
2732 printf(term_quit());
2736 if (load_modules(0)) {
2737 printf(term_quit());
2741 dnsmgr_start_refresh();
2743 /* We might have the option of showing a console, but for now just
2745 if (ast_opt_console && !option_verbose)
2746 ast_verbose(" ]\n");
2747 if (option_verbose || ast_opt_console)
2748 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2749 if (ast_opt_no_fork)
2750 consolethread = pthread_self();
2752 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2753 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2755 #ifdef __AST_DEBUG_MALLOC
2759 time(&ast_startuptime);
2760 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
2762 if (ast_opt_console) {
2763 /* Console stuff now... */
2764 /* Register our quit function */
2766 set_icon("Asterisk");
2767 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2771 buf = (char *)el_gets(el, &num);
2773 if (buf[strlen(buf)-1] == '\n')
2774 buf[strlen(buf)-1] = '\0';
2776 consolehandler((char *)buf);
2777 } else if (ast_opt_remote && (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2778 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0)) {
2779 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2781 fd = open("/dev/null", O_RDWR);
2783 dup2(fd, STDOUT_FILENO);
2784 dup2(fd, STDIN_FILENO);
2786 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2793 for (;;) { /* apparently needed for Mac OS X */
2794 struct pollfd p = { -1 /* no descriptor */, 0, 0 };