2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
22 * \mainpage Asterisk -- An Open Source Telephony Toolkit
24 * \par Developer Documentation for Asterisk
25 * This is the main developer documentation for Asterisk. It is
26 * generated by running "make progdocs".
27 * \par Additional documentation
29 * \arg \ref ConfigFiles
31 * \section copyright Copyright and author
33 * Copyright (C) 1999 - 2006, Digium, Inc.
34 * Asterisk is a trade mark registered by Digium, Inc.
36 * \author Mark Spencer <markster@digium.com>
37 * Also see \ref AstCREDITS
39 * \section license License
40 * See http://www.asterisk.org for more information about
41 * the Asterisk project. Please do not directly contact
42 * any of the maintainers of this project for assistance;
43 * the project provides a web site, mailing lists and IRC
44 * channels for your use.
46 * This program is free software, distributed under the terms of
47 * the GNU General Public License Version 2. See the LICENSE file
48 * at the top of the source tree.
50 * \verbinclude LICENSE
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
71 #include <sys/socket.h>
77 #include <sys/resource.h>
82 #include <sys/prctl.h>
87 #include <sys/prctl.h>
90 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
93 int daemon(int, int); /* defined in libresolv of all places */
97 #include "asterisk/logger.h"
98 #include "asterisk/options.h"
99 #include "asterisk/cli.h"
100 #include "asterisk/channel.h"
101 #include "asterisk/ulaw.h"
102 #include "asterisk/alaw.h"
103 #include "asterisk/callerid.h"
104 #include "asterisk/image.h"
105 #include "asterisk/tdd.h"
106 #include "asterisk/term.h"
107 #include "asterisk/manager.h"
108 #include "asterisk/cdr.h"
109 #include "asterisk/pbx.h"
110 #include "asterisk/enum.h"
111 #include "asterisk/rtp.h"
112 #include "asterisk/http.h"
113 #include "asterisk/udptl.h"
114 #include "asterisk/app.h"
115 #include "asterisk/lock.h"
116 #include "asterisk/utils.h"
117 #include "asterisk/file.h"
118 #include "asterisk/io.h"
119 #include "asterisk/lock.h"
120 #include "editline/histedit.h"
121 #include "asterisk/config.h"
122 #include "asterisk/version.h"
123 #include "asterisk/linkedlists.h"
124 #include "asterisk/devicestate.h"
126 #include "asterisk/doxyref.h" /* Doxygen documentation */
128 #include "../defaults.h"
131 #define AF_LOCAL AF_UNIX
132 #define PF_LOCAL PF_UNIX
135 #define AST_MAX_CONNECTS 128
138 /*! \brief Welcome message when starting a CLI interface */
139 #define WELCOME_MESSAGE \
140 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
141 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
142 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
143 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
144 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
145 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
146 ast_verbose("=========================================================================\n")
148 /*! \defgroup main_options
149 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
150 the operating system command line when starting Asterisk
151 Some of them can be changed in the CLI
155 extern int ast_language_is_prefix; /* XXX move to some header */
157 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
159 int option_verbose = 0; /*!< Verbosity level */
160 int option_debug = 0; /*!< Debug level */
162 double option_maxload = 0.0; /*!< Max load avg on system */
163 int option_maxcalls = 0; /*!< Max number of active calls */
167 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
168 char debug_filename[AST_FILENAME_MAX] = "";
170 static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
171 static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
174 int fd; /*!< File descriptor */
175 int p[2]; /*!< Pipe */
176 pthread_t t; /*!< Thread of handler */
177 int mute; /*!< Is the console muted for logs */
182 AST_LIST_ENTRY(ast_atexit) list;
185 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
187 time_t ast_startuptime;
188 time_t ast_lastreloadtime;
190 static History *el_hist = NULL;
191 static EditLine *el = NULL;
192 static char *remotehostname;
194 struct console consoles[AST_MAX_CONNECTS];
196 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
198 static int ast_el_add_history(char *);
199 static int ast_el_read_history(char *);
200 static int ast_el_write_history(char *);
202 char ast_config_AST_CONFIG_DIR[PATH_MAX];
203 char ast_config_AST_CONFIG_FILE[PATH_MAX];
204 char ast_config_AST_MODULE_DIR[PATH_MAX];
205 char ast_config_AST_SPOOL_DIR[PATH_MAX];
206 char ast_config_AST_MONITOR_DIR[PATH_MAX];
207 char ast_config_AST_VAR_DIR[PATH_MAX];
208 char ast_config_AST_DATA_DIR[PATH_MAX];
209 char ast_config_AST_LOG_DIR[PATH_MAX];
210 char ast_config_AST_AGI_DIR[PATH_MAX];
211 char ast_config_AST_DB[PATH_MAX];
212 char ast_config_AST_KEY_DIR[PATH_MAX];
213 char ast_config_AST_PID[PATH_MAX];
214 char ast_config_AST_SOCKET[PATH_MAX];
215 char ast_config_AST_RUN_DIR[PATH_MAX];
216 char ast_config_AST_RUN_USER[PATH_MAX];
217 char ast_config_AST_RUN_GROUP[PATH_MAX];
218 char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
219 char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
220 char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
221 char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
222 char ast_config_AST_SYSTEM_NAME[20] = "";
224 extern const char *ast_build_hostname;
225 extern const char *ast_build_kernel;
226 extern const char *ast_build_machine;
227 extern const char *ast_build_os;
228 extern const char *ast_build_date;
229 extern const char *ast_build_user;
231 static char *_argv[256];
232 static int shuttingdown = 0;
233 static int restartnow = 0;
234 static pthread_t consolethread = AST_PTHREADT_NULL;
236 static char randompool[256];
238 #if !defined(LOW_MEMORY)
239 struct file_version {
240 AST_LIST_ENTRY(file_version) list;
245 static AST_LIST_HEAD_STATIC(file_versions, file_version);
247 void ast_register_file_version(const char *file, const char *version)
249 struct file_version *new;
251 size_t version_length;
253 work = ast_strdupa(version);
254 work = ast_strip(ast_strip_quoted(work, "$", "$"));
255 version_length = strlen(work) + 1;
257 if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
261 new->version = (char *) new + sizeof(*new);
262 memcpy(new->version, work, version_length);
263 AST_LIST_LOCK(&file_versions);
264 AST_LIST_INSERT_HEAD(&file_versions, new, list);
265 AST_LIST_UNLOCK(&file_versions);
268 void ast_unregister_file_version(const char *file)
270 struct file_version *find;
272 AST_LIST_LOCK(&file_versions);
273 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
274 if (!strcasecmp(find->file, file)) {
275 AST_LIST_REMOVE_CURRENT(&file_versions, list);
279 AST_LIST_TRAVERSE_SAFE_END;
280 AST_LIST_UNLOCK(&file_versions);
285 struct thread_list_t {
286 AST_LIST_ENTRY(thread_list_t) list;
291 static AST_LIST_HEAD_STATIC(thread_list, thread_list_t);
293 static char show_threads_help[] =
294 "Usage: show threads\n"
295 " List threads currently active in the system.\n";
297 void ast_register_thread(char *name)
299 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
303 new->id = pthread_self();
304 new->name = name; /* this was a copy already */
305 AST_LIST_LOCK(&thread_list);
306 AST_LIST_INSERT_HEAD(&thread_list, new, list);
307 AST_LIST_UNLOCK(&thread_list);
310 void ast_unregister_thread(void *id)
312 struct thread_list_t *x;
314 AST_LIST_LOCK(&thread_list);
315 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
316 if ((void *)x->id == id) {
317 AST_LIST_REMOVE_CURRENT(&thread_list, list);
321 AST_LIST_TRAVERSE_SAFE_END;
322 AST_LIST_UNLOCK(&thread_list);
329 static int handle_show_threads(int fd, int argc, char *argv[])
332 struct thread_list_t *cur;
334 AST_LIST_LOCK(&thread_list);
335 AST_LIST_TRAVERSE(&thread_list, cur, list) {
336 ast_cli(fd, "%p %s\n", (void *)cur->id, cur->name);
339 AST_LIST_UNLOCK(&thread_list);
340 ast_cli(fd, "%d threads listed.\n", count);
344 struct profile_entry {
346 uint64_t scale; /* if non-zero, values are scaled by this */
352 struct profile_data {
355 struct profile_entry e[0];
358 static struct profile_data *prof_data;
360 /*! \brief allocates a counter with a given name and scale.
361 * \return Returns the identifier of the counter.
363 int ast_add_profile(const char *name, uint64_t scale)
365 int l = sizeof(struct profile_data);
366 int n = 10; /* default entries */
368 if (prof_data == NULL) {
369 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
370 if (prof_data == NULL)
372 prof_data->entries = 0;
373 prof_data->max_size = n;
375 if (prof_data->entries >= prof_data->max_size) {
377 n = prof_data->max_size + 20;
378 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
382 prof_data->max_size = n;
384 n = prof_data->entries++;
385 prof_data->e[n].name = ast_strdup(name);
386 prof_data->e[n].value = 0;
387 prof_data->e[n].events = 0;
388 prof_data->e[n].mark = 0;
389 prof_data->e[n].scale = scale;
393 int64_t ast_profile(int i, int64_t delta)
395 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
397 if (prof_data->e[i].scale > 1)
398 delta /= prof_data->e[i].scale;
399 prof_data->e[i].value += delta;
400 prof_data->e[i].events++;
401 return prof_data->e[i].value;
404 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
405 #if defined(__FreeBSD__)
406 #include <machine/cpufunc.h>
408 static __inline uint64_t
413 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
417 #else /* supply a dummy function on other platforms */
418 static __inline uint64_t
425 int64_t ast_mark(int i, int startstop)
427 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
430 prof_data->e[i].mark = rdtsc();
432 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
433 if (prof_data->e[i].scale > 1)
434 prof_data->e[i].mark /= prof_data->e[i].scale;
435 prof_data->e[i].value += prof_data->e[i].mark;
436 prof_data->e[i].events++;
438 return prof_data->e[i].mark;
441 static int handle_show_profile(int fd, int argc, char *argv[])
446 if (prof_data == NULL)
450 max = prof_data->entries;
451 if (argc >= 3) { /* specific entries */
452 if (isdigit(argv[2][0])) {
454 if (argc == 4 && strcmp(argv[3], "-"))
459 if (max > prof_data->entries)
460 max = prof_data->entries;
461 if (!strcmp(argv[1], "clear")) {
462 for (i= min; i < max; i++) {
463 if (!search || strstr(prof_data->e[i].name, search)) {
464 prof_data->e[i].value = 0;
465 prof_data->e[i].events = 0;
470 ast_cli(fd, "profile values (%d, allocated %d)\n-------------------\n",
471 prof_data->entries, prof_data->max_size);
472 ast_cli(fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
473 "Value", "Average", "Name");
474 for (i = min; i < max; i++) {
475 struct profile_entry *e = &prof_data->e[i];
476 if (!search || strstr(prof_data->e[i].name, search))
477 ast_cli(fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
480 (long)e->events, (long long)e->value,
481 (long long)(e->events ? e->value / e->events : e->value),
487 static char show_version_files_help[] =
488 "Usage: file list version [like <pattern>]\n"
489 " Lists the revision numbers of the files used to build this copy of Asterisk.\n"
490 " Optional regular expression pattern is used to filter the file list.\n";
492 /*! \brief CLI command to list module versions */
493 static int handle_show_version_files(int fd, int argc, char *argv[])
495 #define FORMAT "%-25.25s %-40.40s\n"
496 struct file_version *iterator;
504 if (!strcasecmp(argv[3], "like")) {
505 if (regcomp(®exbuf, argv[4], REG_EXTENDED | REG_NOSUB))
506 return RESULT_SHOWUSAGE;
509 return RESULT_SHOWUSAGE;
517 return RESULT_SHOWUSAGE;
520 ast_cli(fd, FORMAT, "File", "Revision");
521 ast_cli(fd, FORMAT, "----", "--------");
522 AST_LIST_LOCK(&file_versions);
523 AST_LIST_TRAVERSE(&file_versions, iterator, list) {
524 if (havename && strcasecmp(iterator->file, argv[3]))
527 if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
530 ast_cli(fd, FORMAT, iterator->file, iterator->version);
535 AST_LIST_UNLOCK(&file_versions);
537 ast_cli(fd, "%d files listed.\n", count_files);
543 return RESULT_SUCCESS;
547 static char *complete_show_version_files(const char *line, const char *word, int pos, int state)
549 struct file_version *find;
552 int matchlen = strlen(word);
557 AST_LIST_LOCK(&file_versions);
558 AST_LIST_TRAVERSE(&file_versions, find, list) {
559 if (!strncasecmp(word, find->file, matchlen) && ++which > state) {
560 ret = ast_strdup(find->file);
564 AST_LIST_UNLOCK(&file_versions);
568 #endif /* ! LOW_MEMORY */
570 int ast_register_atexit(void (*func)(void))
573 struct ast_atexit *ae;
574 ast_unregister_atexit(func);
575 AST_LIST_LOCK(&atexits);
576 if ((ae = ast_calloc(1, sizeof(*ae)))) {
577 AST_LIST_INSERT_HEAD(&atexits, ae, list);
581 AST_LIST_UNLOCK(&atexits);
585 void ast_unregister_atexit(void (*func)(void))
587 struct ast_atexit *ae;
588 AST_LIST_LOCK(&atexits);
589 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
590 if (ae->func == func) {
591 AST_LIST_REMOVE_CURRENT(&atexits, list);
595 AST_LIST_TRAVERSE_SAFE_END
596 AST_LIST_UNLOCK(&atexits);
599 static int fdprint(int fd, const char *s)
601 return write(fd, s, strlen(s) + 1);
604 /*! \brief NULL handler so we can collect the child exit status */
605 static void null_sig_handler(int signal)
610 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
611 /*! \brief Keep track of how many threads are currently trying to wait*() on
613 static unsigned int safe_system_level = 0;
614 static void *safe_system_prev_handler;
616 void ast_replace_sigchld(void)
620 ast_mutex_lock(&safe_system_lock);
621 level = safe_system_level++;
623 /* only replace the handler if it has not already been done */
625 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
627 ast_mutex_unlock(&safe_system_lock);
630 void ast_unreplace_sigchld(void)
634 ast_mutex_lock(&safe_system_lock);
635 level = --safe_system_level;
637 /* only restore the handler if we are the last one */
639 signal(SIGCHLD, safe_system_prev_handler);
641 ast_mutex_unlock(&safe_system_lock);
644 int ast_safe_system(const char *s)
649 struct rusage rusage;
652 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
653 ast_replace_sigchld();
655 #ifdef HAVE_WORKING_FORK
662 if (ast_opt_high_priority)
664 /* Close file descriptors and launch system command */
665 for (x = STDERR_FILENO + 1; x < 4096; x++)
667 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
669 } else if (pid > 0) {
671 res = wait4(pid, &status, 0, &rusage);
673 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
675 } else if (errno != EINTR)
679 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
683 ast_unreplace_sigchld();
692 * \brief mute or unmute a console from logging
694 void ast_console_toggle_mute(int fd) {
696 for (x = 0;x < AST_MAX_CONNECTS; x++) {
697 if (fd == consoles[x].fd) {
698 if (consoles[x].mute) {
699 consoles[x].mute = 0;
700 ast_cli(fd, "Console is not muted anymore.\n");
702 consoles[x].mute = 1;
703 ast_cli(fd, "Console is muted.\n");
708 ast_cli(fd, "Couldn't find remote console.\n");
712 * \brief log the string to all attached console clients
714 static void ast_network_puts_mutable(const char *string)
717 for (x = 0;x < AST_MAX_CONNECTS; x++) {
718 if (consoles[x].mute)
720 if (consoles[x].fd > -1)
721 fdprint(consoles[x].p[1], string);
726 * \brief log the string to the console, and all attached
729 void ast_console_puts_mutable(const char *string)
731 fputs(string, stdout);
733 ast_network_puts_mutable(string);
737 * \brief write the string to all attached console clients
739 static void ast_network_puts(const char *string)
742 for (x=0; x < AST_MAX_CONNECTS; x++) {
743 if (consoles[x].fd > -1)
744 fdprint(consoles[x].p[1], string);
749 * write the string to the console, and all attached
752 void ast_console_puts(const char *string)
754 fputs(string, stdout);
756 ast_network_puts(string);
759 static void network_verboser(const char *s)
761 ast_network_puts_mutable(s);
764 static pthread_t lthread;
766 static void *netconsole(void *vconsole)
768 struct console *con = vconsole;
769 char hostname[MAXHOSTNAMELEN] = "";
772 struct pollfd fds[2];
774 if (gethostname(hostname, sizeof(hostname)-1))
775 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
776 snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ASTERISK_VERSION);
777 fdprint(con->fd, tmp);
780 fds[0].events = POLLIN;
782 fds[1].fd = con->p[0];
783 fds[1].events = POLLIN;
786 res = poll(fds, 2, -1);
789 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
792 if (fds[0].revents) {
793 res = read(con->fd, tmp, sizeof(tmp));
798 ast_cli_command(con->fd, tmp);
800 if (fds[1].revents) {
801 res = read(con->p[0], tmp, sizeof(tmp));
803 ast_log(LOG_ERROR, "read returned %d\n", res);
806 res = write(con->fd, tmp, res);
811 if (option_verbose > 2)
812 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
821 static void *listener(void *unused)
823 struct sockaddr_un sunaddr;
828 struct pollfd fds[1];
830 pthread_attr_init(&attr);
831 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
835 fds[0].fd = ast_socket;
836 fds[0].events = POLLIN;
837 s = poll(fds, 1, -1);
838 pthread_testcancel();
841 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
844 len = sizeof(sunaddr);
845 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
848 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
850 for (x = 0; x < AST_MAX_CONNECTS; x++) {
851 if (consoles[x].fd < 0) {
852 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
853 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
855 fdprint(s, "Server failed to create pipe\n");
859 flags = fcntl(consoles[x].p[1], F_GETFL);
860 fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
862 consoles[x].mute = ast_opt_mute;
863 if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
864 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
865 close(consoles[x].p[0]);
866 close(consoles[x].p[1]);
868 fdprint(s, "Server failed to spawn thread\n");
874 if (x >= AST_MAX_CONNECTS) {
875 fdprint(s, "No more connections allowed\n");
876 ast_log(LOG_WARNING, "No more connections allowed\n");
878 } else if (consoles[x].fd > -1) {
879 if (option_verbose > 2)
880 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
887 static int ast_makesocket(void)
889 struct sockaddr_un sunaddr;
895 for (x = 0; x < AST_MAX_CONNECTS; x++)
897 unlink(ast_config_AST_SOCKET);
898 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
899 if (ast_socket < 0) {
900 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
903 memset(&sunaddr, 0, sizeof(sunaddr));
904 sunaddr.sun_family = AF_LOCAL;
905 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
906 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
908 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
913 res = listen(ast_socket, 2);
915 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
920 ast_register_verbose(network_verboser);
921 ast_pthread_create(<hread, NULL, listener, NULL);
923 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
925 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
926 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
932 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
934 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
935 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
941 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
942 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
944 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
947 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
949 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
950 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
956 static int ast_tryconnect(void)
958 struct sockaddr_un sunaddr;
960 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
961 if (ast_consock < 0) {
962 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
965 memset(&sunaddr, 0, sizeof(sunaddr));
966 sunaddr.sun_family = AF_LOCAL;
967 ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
968 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
977 /*! \brief Urgent handler
979 Called by soft_hangup to interrupt the poll, read, or other
980 system call. We don't actually need to do anything though.
981 Remember: Cannot EVER ast_log from within a signal handler
983 static void urg_handler(int num)
985 signal(num, urg_handler);
989 static void hup_handler(int num)
991 if (option_verbose > 1)
992 printf("Received HUP signal -- Reloading configs\n");
994 execvp(_argv[0], _argv);
995 /* XXX This could deadlock XXX */
996 ast_module_reload(NULL);
997 signal(num, hup_handler);
1000 static void child_handler(int sig)
1002 /* Must not ever ast_log or ast_verbose within signal handler */
1006 * Reap all dead children -- not just one
1008 for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1010 if (n == 0 && option_debug)
1011 printf("Huh? Child handler, but nobody there?\n");
1012 signal(sig, child_handler);
1015 /*! \brief Set an X-term or screen title */
1016 static void set_title(char *text)
1018 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1019 fprintf(stdout, "\033]2;%s\007", text);
1022 static void set_icon(char *text)
1024 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1025 fprintf(stdout, "\033]1;%s\007", text);
1028 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1029 else. If your PBX has heavy activity on it, this is a good thing. */
1030 int ast_set_priority(int pri)
1032 struct sched_param sched;
1033 memset(&sched, 0, sizeof(sched));
1036 sched.sched_priority = 10;
1037 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1038 ast_log(LOG_WARNING, "Unable to set high priority\n");
1042 ast_verbose("Set to realtime thread\n");
1044 sched.sched_priority = 0;
1045 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
1046 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1052 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1053 ast_log(LOG_WARNING, "Unable to set high priority\n");
1057 ast_verbose("Set to high priority\n");
1059 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
1060 ast_log(LOG_WARNING, "Unable to set normal priority\n");
1068 static void ast_run_atexits(void)
1070 struct ast_atexit *ae;
1071 AST_LIST_LOCK(&atexits);
1072 AST_LIST_TRAVERSE(&atexits, ae, list) {
1076 AST_LIST_UNLOCK(&atexits);
1079 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1081 char filename[80] = "";
1084 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1085 ast_cdr_engine_term();
1089 /* Begin shutdown routine, hanging up active channels */
1090 ast_begin_shutdown(1);
1091 if (option_verbose && ast_opt_console)
1092 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1096 /* Wait up to 15 seconds for all channels to go away */
1099 if (!ast_active_channels())
1103 /* Sleep 1/10 of a second */
1108 ast_begin_shutdown(0);
1109 if (option_verbose && ast_opt_console)
1110 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1112 if (!ast_active_channels())
1120 if (!shuttingdown) {
1121 if (option_verbose && ast_opt_console)
1122 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1126 if (ast_opt_console || ast_opt_remote) {
1128 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1129 if (!ast_strlen_zero(filename))
1130 ast_el_write_history(filename);
1133 if (el_hist != NULL)
1134 history_end(el_hist);
1137 ast_verbose("Executing last minute cleanups\n");
1139 /* Called on exit */
1140 if (option_verbose && ast_opt_console)
1141 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1143 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
1144 manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1145 if (ast_socket > -1) {
1146 pthread_cancel(lthread);
1149 unlink(ast_config_AST_SOCKET);
1151 if (ast_consock > -1)
1153 if (!ast_opt_remote)
1154 unlink(ast_config_AST_PID);
1155 printf(term_quit());
1157 if (option_verbose || ast_opt_console)
1158 ast_verbose("Preparing for Asterisk restart...\n");
1159 /* Mark all FD's for closing on exec */
1160 for (x=3; x < 32768; x++) {
1161 fcntl(x, F_SETFD, FD_CLOEXEC);
1163 if (option_verbose || ast_opt_console)
1164 ast_verbose("Restarting Asterisk NOW...\n");
1170 /* If there is a consolethread running send it a SIGHUP
1171 so it can execvp, otherwise we can do it ourselves */
1172 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1173 pthread_kill(consolethread, SIGHUP);
1174 /* Give the signal handler some time to complete */
1177 execvp(_argv[0], _argv);
1186 static void __quit_handler(int num)
1188 quit_handler(num, 0, 1, 0);
1191 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1194 if (!strncmp(s, cmp, strlen(cmp))) {
1195 c = s + strlen(cmp);
1196 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1202 static void console_verboser(const char *s)
1205 const char *c = NULL;
1207 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1208 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1209 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1210 (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1218 /* Wake up a poll()ing console */
1219 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1220 pthread_kill(consolethread, SIGURG);
1223 static int ast_all_zeros(char *s)
1233 static void consolehandler(char *s)
1238 /* Called when readline data is available */
1239 if (!ast_all_zeros(s))
1240 ast_el_add_history(s);
1241 /* The real handler for bang */
1244 ast_safe_system(s+1);
1246 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1248 ast_cli_command(STDOUT_FILENO, s);
1251 static int remoteconsolehandler(char *s)
1255 /* Called when readline data is available */
1256 if (!ast_all_zeros(s))
1257 ast_el_add_history(s);
1258 /* The real handler for bang */
1261 ast_safe_system(s+1);
1263 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1266 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1267 (s[4] == '\0' || isspace(s[4]))) {
1268 quit_handler(0, 0, 0, 0);
1275 static char abort_halt_help[] =
1276 "Usage: abort shutdown\n"
1277 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1278 " call operations.\n";
1280 static char shutdown_now_help[] =
1282 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1284 static char shutdown_gracefully_help[] =
1285 "Usage: stop gracefully\n"
1286 " Causes Asterisk to not accept new calls, and exit when all\n"
1287 " active calls have terminated normally.\n";
1289 static char shutdown_when_convenient_help[] =
1290 "Usage: stop when convenient\n"
1291 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1293 static char restart_now_help[] =
1294 "Usage: restart now\n"
1295 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1298 static char restart_gracefully_help[] =
1299 "Usage: restart gracefully\n"
1300 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1301 " restart when all active calls have ended.\n";
1303 static char restart_when_convenient_help[] =
1304 "Usage: restart when convenient\n"
1305 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1307 static char bang_help[] =
1308 "Usage: !<command>\n"
1309 " Executes a given shell command\n";
1311 static char show_warranty_help[] =
1312 "Usage: show warranty\n"
1313 " Shows the warranty (if any) for this copy of Asterisk.\n";
1315 static char show_license_help[] =
1316 "Usage: show license\n"
1317 " Shows the license(s) for this copy of Asterisk.\n";
1319 static char version_help[] =
1320 "Usage: show version\n"
1321 " Shows Asterisk version information.\n";
1323 static int handle_version(int fd, int argc, char *argv[])
1326 return RESULT_SHOWUSAGE;
1327 ast_cli(fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1328 ASTERISK_VERSION, ast_build_user, ast_build_hostname,
1329 ast_build_machine, ast_build_os, ast_build_date);
1330 return RESULT_SUCCESS;
1334 static int handle_quit(int fd, int argc, char *argv[])
1337 return RESULT_SHOWUSAGE;
1338 quit_handler(0, 0, 1, 0);
1339 return RESULT_SUCCESS;
1343 static int handle_shutdown_now(int fd, int argc, char *argv[])
1346 return RESULT_SHOWUSAGE;
1347 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1348 return RESULT_SUCCESS;
1351 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1354 return RESULT_SHOWUSAGE;
1355 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1356 return RESULT_SUCCESS;
1359 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1362 return RESULT_SHOWUSAGE;
1363 ast_cli(fd, "Waiting for inactivity to perform halt\n");
1364 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1365 return RESULT_SUCCESS;
1368 static int handle_restart_now(int fd, int argc, char *argv[])
1371 return RESULT_SHOWUSAGE;
1372 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1373 return RESULT_SUCCESS;
1376 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1379 return RESULT_SHOWUSAGE;
1380 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1381 return RESULT_SUCCESS;
1384 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1387 return RESULT_SHOWUSAGE;
1388 ast_cli(fd, "Waiting for inactivity to perform restart\n");
1389 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1390 return RESULT_SUCCESS;
1393 static int handle_abort_halt(int fd, int argc, char *argv[])
1396 return RESULT_SHOWUSAGE;
1397 ast_cancel_shutdown();
1399 return RESULT_SUCCESS;
1402 static int handle_bang(int fd, int argc, char *argv[])
1404 return RESULT_SUCCESS;
1406 static const char *warranty_lines[] = {
1410 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1411 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1412 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1413 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1414 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1415 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1416 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1417 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1418 "REPAIR OR CORRECTION.\n",
1420 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1421 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1422 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1423 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1424 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1425 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1426 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1427 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1428 "POSSIBILITY OF SUCH DAMAGES.\n",
1431 static int show_warranty(int fd, int argc, char *argv[])
1435 for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1436 ast_cli(fd, (char *) warranty_lines[x]);
1438 return RESULT_SUCCESS;
1441 static const char *license_lines[] = {
1443 "This program is free software; you can redistribute it and/or modify\n",
1444 "it under the terms of the GNU General Public License version 2 as\n",
1445 "published by the Free Software Foundation.\n",
1447 "This program also contains components licensed under other licenses.\n",
1450 "This program is distributed in the hope that it will be useful,\n",
1451 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1452 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1453 "GNU General Public License for more details.\n",
1455 "You should have received a copy of the GNU General Public License\n",
1456 "along with this program; if not, write to the Free Software\n",
1457 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1460 static int show_license(int fd, int argc, char *argv[])
1464 for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1465 ast_cli(fd, (char *) license_lines[x]);
1467 return RESULT_SUCCESS;
1470 #define ASTERISK_PROMPT "*CLI> "
1472 #define ASTERISK_PROMPT2 "%s*CLI> "
1474 static struct ast_cli_entry cli_asterisk[] = {
1475 { { "abort", "halt", NULL },
1476 handle_abort_halt, "Cancel a running halt",
1479 { { "stop", "now", NULL },
1480 handle_shutdown_now, "Shut down Asterisk immediately",
1481 shutdown_now_help },
1483 { { "stop", "gracefully", NULL },
1484 handle_shutdown_gracefully, "Gracefully shut down Asterisk",
1485 shutdown_gracefully_help },
1487 { { "stop", "when", "convenient", NULL },
1488 handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume",
1489 shutdown_when_convenient_help },
1491 { { "restart", "now", NULL },
1492 handle_restart_now, "Restart Asterisk immediately", restart_now_help },
1494 { { "restart", "gracefully", NULL },
1495 handle_restart_gracefully, "Restart Asterisk gracefully",
1496 restart_gracefully_help },
1498 { { "restart", "when", "convenient", NULL },
1499 handle_restart_when_convenient, "Restart Asterisk at empty call volume",
1500 restart_when_convenient_help },
1502 { { "show", "warranty", NULL },
1503 show_warranty, "Show the warranty (if any) for this copy of Asterisk",
1504 show_warranty_help },
1506 { { "show", "license", NULL },
1507 show_license, "Show the license(s) for this copy of Asterisk",
1508 show_license_help },
1510 { { "show", "version", NULL },
1511 handle_version, "Display version info",
1515 handle_bang, "Execute a shell command",
1518 #if !defined(LOW_MEMORY)
1519 { { "file", "list", "version", NULL },
1520 handle_show_version_files, "List versions of files used to build Asterisk",
1521 show_version_files_help, complete_show_version_files },
1523 { { "show", "threads", NULL },
1524 handle_show_threads, "Show running threads",
1525 show_threads_help },
1527 { { "profile", "list", NULL },
1528 handle_show_profile, "Display profiling info",
1531 { { "profile", "clear", NULL },
1532 handle_show_profile, "Clear profiling info",
1534 #endif /* ! LOW_MEMORY */
1537 static int ast_el_read_char(EditLine *el, char *cp)
1541 struct pollfd fds[2];
1548 fds[0].fd = ast_consock;
1549 fds[0].events = POLLIN;
1550 if (!ast_opt_exec) {
1551 fds[1].fd = STDIN_FILENO;
1552 fds[1].events = POLLIN;
1555 res = poll(fds, max, -1);
1559 ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1563 if (!ast_opt_exec && fds[1].revents) {
1564 num_read = read(STDIN_FILENO, cp, 1);
1570 if (fds[0].revents) {
1571 res = read(ast_consock, buf, sizeof(buf) - 1);
1572 /* if the remote side disappears exit */
1574 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1575 if (!ast_opt_reconnect) {
1576 quit_handler(0, 0, 0, 0);
1579 int reconnects_per_second = 20;
1580 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1581 for (tries=0; tries < 30 * reconnects_per_second; tries++) {
1582 if (ast_tryconnect()) {
1583 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1584 printf(term_quit());
1588 usleep(1000000 / reconnects_per_second);
1591 if (tries >= 30 * reconnects_per_second) {
1592 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
1593 quit_handler(0, 0, 0, 0);
1600 if (!ast_opt_exec && !lastpos)
1601 write(STDOUT_FILENO, "\r", 1);
1602 write(STDOUT_FILENO, buf, res);
1603 if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1616 static char *cli_prompt(EditLine *el)
1618 static char prompt[200];
1623 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1624 char *t = pfmt, *p = prompt;
1625 memset(prompt, 0, sizeof(prompt));
1626 while (*t != '\0' && *p < sizeof(prompt)) {
1628 char hostname[MAXHOSTNAMELEN]="";
1635 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1639 case 'C': /* color */
1641 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1642 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1644 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1645 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1649 /* If the color has been reset correctly, then there's no need to reset it later */
1650 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1656 case 'd': /* date */
1657 memset(&tm, 0, sizeof(tm));
1659 if (localtime_r(&ts, &tm)) {
1660 strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1663 case 'h': /* hostname */
1664 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1665 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1667 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1670 case 'H': /* short hostname */
1671 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1672 for (i = 0; i < sizeof(hostname); i++) {
1673 if (hostname[i] == '.') {
1678 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1680 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1684 case 'l': /* load avg */
1686 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1687 float avg1, avg2, avg3;
1688 int actproc, totproc, npid, which;
1689 fscanf(LOADAVG, "%f %f %f %d/%d %d",
1690 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1691 if (sscanf(t, "%d", &which) == 1) {
1694 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1697 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1700 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1703 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1706 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1713 case 's': /* Asterisk system name (from asterisk.conf) */
1714 strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
1716 case 't': /* time */
1717 memset(&tm, 0, sizeof(tm));
1719 if (localtime_r(&ts, &tm)) {
1720 strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1723 case '#': /* process console or remote? */
1724 if (!ast_opt_remote) {
1725 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1727 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1730 case '%': /* literal % */
1731 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1733 case '\0': /* % is last character - prevent bug */
1737 while (*p != '\0') {
1748 /* Force colors back to normal at end */
1749 term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1750 if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1751 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1753 strncat(p, term_code, sizeof(term_code));
1756 } else if (remotehostname)
1757 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1759 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1764 static char **ast_el_strtoarr(char *buf)
1766 char **match_list = NULL, *retstr;
1767 size_t match_list_len;
1771 while ( (retstr = strsep(&buf, " ")) != NULL) {
1773 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1775 if (matches + 1 >= match_list_len) {
1776 match_list_len <<= 1;
1777 if (!(match_list = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
1778 /* TODO: Handle memory allocation failure */
1782 match_list[matches++] = strdup(retstr);
1786 return (char **) NULL;
1788 if (matches >= match_list_len) {
1789 if (!(match_list = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
1790 /* TODO: Handle memory allocation failure */
1794 match_list[matches] = (char *) NULL;
1799 static int ast_el_sort_compare(const void *i1, const void *i2)
1803 s1 = ((char **)i1)[0];
1804 s2 = ((char **)i2)[0];
1806 return strcasecmp(s1, s2);
1809 static int ast_cli_display_match_list(char **matches, int len, int max)
1811 int i, idx, limit, count;
1812 int screenwidth = 0;
1813 int numoutput = 0, numoutputline = 0;
1815 screenwidth = ast_get_termcols(STDOUT_FILENO);
1817 /* find out how many entries can be put on one line, with two spaces between strings */
1818 limit = screenwidth / (max + 2);
1822 /* how many lines of output */
1823 count = len / limit;
1824 if (count * limit < len)
1829 qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1831 for (; count > 0; count--) {
1833 for (i=0; i < limit && matches[idx]; i++, idx++) {
1835 /* Don't print dupes */
1836 if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1839 matches[idx] = NULL;
1845 fprintf(stdout, "%-*s ", max, matches[idx]);
1847 matches[idx] = NULL;
1849 if (numoutputline > 0)
1850 fprintf(stdout, "\n");
1857 static char *cli_complete(EditLine *el, int ch)
1863 int retval = CC_ERROR;
1867 LineInfo *lf = (LineInfo *)el_line(el);
1869 *(char *)lf->cursor = '\0';
1870 ptr = (char *)lf->cursor;
1872 while (ptr > lf->buffer) {
1873 if (isspace(*ptr)) {
1881 len = lf->cursor - ptr;
1883 if (ast_opt_remote) {
1884 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
1885 fdprint(ast_consock, buf);
1886 res = read(ast_consock, buf, sizeof(buf));
1888 nummatches = atoi(buf);
1890 if (nummatches > 0) {
1892 int mlen = 0, maxmbuf = 2048;
1893 /* Start with a 2048 byte buffer */
1894 if (!(mbuf = ast_malloc(maxmbuf)))
1895 return (char *)(CC_ERROR);
1896 snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
1897 fdprint(ast_consock, buf);
1900 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1901 if (mlen + 1024 > maxmbuf) {
1902 /* Every step increment buffer 1024 bytes */
1904 if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
1905 return (char *)(CC_ERROR);
1907 /* Only read 1024 bytes at a time */
1908 res = read(ast_consock, mbuf + mlen, 1024);
1914 matches = ast_el_strtoarr(mbuf);
1917 matches = (char **) NULL;
1919 char **p, *oldbuf=NULL;
1921 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1922 for (p = matches; p && *p; p++) {
1923 if (!oldbuf || strcmp(*p,oldbuf))
1931 int matches_num, maxlen, match_len;
1933 if (matches[0][0] != '\0') {
1934 el_deletestr(el, (int) len);
1935 el_insertstr(el, matches[0]);
1936 retval = CC_REFRESH;
1939 if (nummatches == 1) {
1940 /* Found an exact match */
1941 el_insertstr(el, " ");
1942 retval = CC_REFRESH;
1944 /* Must be more than one match */
1945 for (i=1, maxlen=0; matches[i]; i++) {
1946 match_len = strlen(matches[i]);
1947 if (match_len > maxlen)
1950 matches_num = i - 1;
1951 if (matches_num >1) {
1952 fprintf(stdout, "\n");
1953 ast_cli_display_match_list(matches, nummatches, maxlen);
1954 retval = CC_REDISPLAY;
1956 el_insertstr(el," ");
1957 retval = CC_REFRESH;
1963 return (char *)(long)retval;
1966 static int ast_el_initialize(void)
1969 char *editor = getenv("AST_EDITOR");
1973 if (el_hist != NULL)
1974 history_end(el_hist);
1976 el = el_init("asterisk", stdin, stdout, stderr);
1977 el_set(el, EL_PROMPT, cli_prompt);
1979 el_set(el, EL_EDITMODE, 1);
1980 el_set(el, EL_EDITOR, editor ? editor : "emacs");
1981 el_hist = history_init();
1982 if (!el || !el_hist)
1985 /* setup history with 100 entries */
1986 history(el_hist, &ev, H_SETSIZE, 100);
1988 el_set(el, EL_HIST, history, el_hist);
1990 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1991 /* Bind <tab> to command completion */
1992 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1993 /* Bind ? to command completion */
1994 el_set(el, EL_BIND, "?", "ed-complete", NULL);
1995 /* Bind ^D to redisplay */
1996 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2001 static int ast_el_add_history(char *buf)
2005 if (el_hist == NULL || el == NULL)
2006 ast_el_initialize();
2007 if (strlen(buf) > 256)
2009 return (history(el_hist, &ev, H_ENTER, buf));
2012 static int ast_el_write_history(char *filename)
2016 if (el_hist == NULL || el == NULL)
2017 ast_el_initialize();
2019 return (history(el_hist, &ev, H_SAVE, filename));
2022 static int ast_el_read_history(char *filename)
2028 if (el_hist == NULL || el == NULL)
2029 ast_el_initialize();
2031 if ((f = fopen(filename, "r")) == NULL)
2035 fgets(buf, sizeof(buf), f);
2036 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2038 if (ast_all_zeros(buf))
2040 if ((ret = ast_el_add_history(buf)) == -1)
2048 static void ast_remotecontrol(char * data)
2052 char filename[80] = "";
2058 char *stringp = NULL;
2063 read(ast_consock, buf, sizeof(buf));
2065 write(ast_consock, data, strlen(data) + 1);
2067 hostname = strsep(&stringp, "/");
2068 cpid = strsep(&stringp, "/");
2069 version = strsep(&stringp, "\n");
2071 version = "<Version Unknown>";
2073 strsep(&stringp, ".");
2078 snprintf(tmp, sizeof(tmp), "core verbose %d", option_verbose);
2079 fdprint(ast_consock, tmp);
2080 snprintf(tmp, sizeof(tmp), "core debug %d", option_debug);
2081 fdprint(ast_consock, tmp);
2083 snprintf(tmp, sizeof(tmp), "log and verbose output currently muted ('logger unmute' to unmute)");
2084 fdprint(ast_consock, tmp);
2086 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2087 remotehostname = hostname;
2089 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2090 if (el_hist == NULL || el == NULL)
2091 ast_el_initialize();
2093 el_set(el, EL_GETCFN, ast_el_read_char);
2095 if (!ast_strlen_zero(filename))
2096 ast_el_read_history(filename);
2098 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
2101 fds.fd = ast_consock;
2102 fds.events = POLLIN;
2104 while (poll(&fds, 1, 100) > 0)
2105 ast_el_read_char(el, &tempchar);
2109 ebuf = (char *)el_gets(el, &num);
2111 if (!ast_strlen_zero(ebuf)) {
2112 if (ebuf[strlen(ebuf)-1] == '\n')
2113 ebuf[strlen(ebuf)-1] = '\0';
2114 if (!remoteconsolehandler(ebuf)) {
2115 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2117 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2123 printf("\nDisconnected from Asterisk server\n");
2126 static int show_version(void)
2128 printf("Asterisk " ASTERISK_VERSION "\n");
2132 static int show_cli_help(void) {
2133 printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2134 printf("Usage: asterisk [OPTIONS]\n");
2135 printf("Valid Options:\n");
2136 printf(" -V Display version number and exit\n");
2137 printf(" -C <configfile> Use an alternate configuration file\n");
2138 printf(" -G <group> Run as a group other than the caller\n");
2139 printf(" -U <user> Run as a user other than the caller\n");
2140 printf(" -c Provide console CLI\n");
2141 printf(" -d Enable extra debugging\n");
2142 #if HAVE_WORKING_FORK
2143 printf(" -f Do not fork\n");
2144 printf(" -F Always fork\n");
2146 printf(" -g Dump core in case of a crash\n");
2147 printf(" -h This help screen\n");
2148 printf(" -i Initialize crypto keys at startup\n");
2149 printf(" -I Enable internal timing if Zaptel timer is available\n");
2150 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2151 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2152 printf(" -m Mute the console from debugging and verbose output\n");
2153 printf(" -n Disable console colorization\n");
2154 printf(" -p Run as pseudo-realtime thread\n");
2155 printf(" -q Quiet mode (suppress output)\n");
2156 printf(" -r Connect to Asterisk on this machine\n");
2157 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2158 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2159 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2160 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2161 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2166 static void ast_readconfig(void)
2168 struct ast_config *cfg;
2169 struct ast_variable *v;
2170 char *config = AST_CONFIG_FILE;
2172 if (ast_opt_override_config) {
2173 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
2175 ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2177 cfg = ast_config_load(config);
2180 /* init with buildtime config */
2181 ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
2182 ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
2183 ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_MODULE_DIR));
2184 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
2185 ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
2186 ast_copy_string(ast_config_AST_DATA_DIR, AST_DATA_DIR, sizeof(ast_config_AST_DATA_DIR));
2187 ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
2188 ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
2189 ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
2190 ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
2191 ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
2192 ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
2193 ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
2195 /* no asterisk.conf? no problem, use buildtime config! */
2200 for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2201 if (!strcasecmp(v->name, "astctlpermissions")) {
2202 ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2203 } else if (!strcasecmp(v->name, "astctlowner")) {
2204 ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2205 } else if (!strcasecmp(v->name, "astctlgroup")) {
2206 ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2207 } else if (!strcasecmp(v->name, "astctl")) {
2208 ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2212 for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2213 if (!strcasecmp(v->name, "astetcdir")) {
2214 ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
2215 } else if (!strcasecmp(v->name, "astspooldir")) {
2216 ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
2217 snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
2218 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2219 ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
2220 snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/astdb", v->value);
2221 } else if (!strcasecmp(v->name, "astdatadir")) {
2222 ast_copy_string(ast_config_AST_DATA_DIR, v->value, sizeof(ast_config_AST_DATA_DIR));
2223 snprintf(ast_config_AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR), "%s/keys", v->value);
2224 } else if (!strcasecmp(v->name, "astlogdir")) {
2225 ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
2226 } else if (!strcasecmp(v->name, "astagidir")) {
2227 ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
2228 } else if (!strcasecmp(v->name, "astrundir")) {
2229 snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
2230 snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
2231 ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
2232 } else if (!strcasecmp(v->name, "astmoddir")) {
2233 ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
2237 for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2238 /* verbose level (-v at startup) */
2239 if (!strcasecmp(v->name, "verbose")) {
2240 option_verbose = atoi(v->value);
2241 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2242 } else if (!strcasecmp(v->name, "timestamp")) {
2243 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2244 /* whether or not to support #exec in config files */
2245 } else if (!strcasecmp(v->name, "execincludes")) {
2246 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2247 /* debug level (-d at startup) */
2248 } else if (!strcasecmp(v->name, "debug")) {
2250 if (sscanf(v->value, "%d", &option_debug) != 1) {
2251 option_debug = ast_true(v->value);
2253 #if HAVE_WORKING_FORK
2254 /* Disable forking (-f at startup) */
2255 } else if (!strcasecmp(v->name, "nofork")) {
2256 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2257 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2258 } else if (!strcasecmp(v->name, "alwaysfork")) {
2259 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2261 /* Run quietly (-q at startup ) */
2262 } else if (!strcasecmp(v->name, "quiet")) {
2263 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2264 /* Run as console (-c at startup, implies nofork) */
2265 } else if (!strcasecmp(v->name, "console")) {
2266 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2267 /* Run with high priority if the O/S permits (-p at startup) */
2268 } else if (!strcasecmp(v->name, "highpriority")) {
2269 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2270 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2271 } else if (!strcasecmp(v->name, "initcrypto")) {
2272 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2273 /* Disable ANSI colors for console (-c at startup) */
2274 } else if (!strcasecmp(v->name, "nocolor")) {
2275 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2276 /* Disable some usage warnings for picky people :p */
2277 } else if (!strcasecmp(v->name, "dontwarn")) {
2278 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2279 /* Dump core in case of crash (-g) */
2280 } else if (!strcasecmp(v->name, "dumpcore")) {
2281 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2282 /* Cache recorded sound files to another directory during recording */
2283 } else if (!strcasecmp(v->name, "cache_record_files")) {
2284 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2285 /* Specify cache directory */
2286 } else if (!strcasecmp(v->name, "record_cache_dir")) {
2287 ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2288 /* Build transcode paths via SLINEAR, instead of directly */
2289 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2290 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2291 /* Transmit SLINEAR silence while a channel is being recorded */
2292 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
2293 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2294 /* Enable internal timing */
2295 } else if (!strcasecmp(v->name, "internal_timing")) {
2296 ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2297 } else if (!strcasecmp(v->name, "maxcalls")) {
2298 if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2299 option_maxcalls = 0;
2301 } else if (!strcasecmp(v->name, "maxload")) {
2304 if (getloadavg(test, 1) == -1) {
2305 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2306 option_maxload = 0.0;
2307 } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2308 option_maxload = 0.0;
2310 /* What user to run as */
2311 } else if (!strcasecmp(v->name, "runuser")) {
2312 ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
2313 /* What group to run as */
2314 } else if (!strcasecmp(v->name, "rungroup")) {
2315 ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
2316 } else if (!strcasecmp(v->name, "systemname")) {
2317 ast_copy_string(ast_config_AST_SYSTEM_NAME, v->value, sizeof(ast_config_AST_SYSTEM_NAME));
2318 } else if (!strcasecmp(v->name, "languageprefix")) {
2319 ast_language_is_prefix = ast_true(v->value);
2322 ast_config_destroy(cfg);
2325 int main(int argc, char *argv[])
2328 char filename[80] = "";
2329 char hostname[MAXHOSTNAMELEN] = "";
2336 int is_child_of_nonroot = 0;
2338 char *runuser = NULL, *rungroup = NULL;
2340 /* Remember original args for restart */
2341 if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2342 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2343 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2345 for (x=0; x<argc; x++)
2349 /* if the progname is rasterisk consider it a remote console */
2350 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2351 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2353 if (gethostname(hostname, sizeof(hostname)-1))
2354 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2355 ast_mainpid = getpid();
2359 ast_builtins_init();
2362 /* When Asterisk restarts after it has dropped the root privileges,
2363 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2365 if (getenv("ASTERISK_ALREADY_NONROOT"))
2366 is_child_of_nonroot=1;
2368 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2369 /* Check for options */
2370 while ((c = getopt(argc, argv, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2372 #if HAVE_WORKING_FORK
2374 ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2377 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2382 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2385 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2388 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2391 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2394 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2397 ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2401 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2404 ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2407 if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2408 option_maxcalls = 0;
2411 if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2412 option_maxload = 0.0;
2415 ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2418 ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2421 ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2424 ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2428 ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2429 ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2432 ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2435 ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2438 ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2457 if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2458 ast_register_verbose(console_verboser);
2462 if (ast_opt_console && !option_verbose)
2463 ast_verbose("[ Booting...\n");
2465 if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2466 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2467 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2470 /* For remote connections, change the name of the remote connection.
2471 * We do this for the benefit of init scripts (which need to know if/when
2472 * the main asterisk process has died yet). */
2473 if (ast_opt_remote) {
2474 strcpy(argv[0], "rasterisk");
2475 for (x = 1; x < argc; x++) {
2476 argv[x] = argv[0] + 10;
2480 if (ast_opt_console && !option_verbose)
2481 ast_verbose("[ Reading Master Configuration ]\n");
2484 if (ast_opt_dump_core) {
2486 memset(&l, 0, sizeof(l));
2487 l.rlim_cur = RLIM_INFINITY;
2488 l.rlim_max = RLIM_INFINITY;
2489 if (setrlimit(RLIMIT_CORE, &l)) {
2490 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2494 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2495 rungroup = ast_config_AST_RUN_GROUP;
2496 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2497 runuser = ast_config_AST_RUN_USER;
2501 if (!is_child_of_nonroot)
2502 ast_set_priority(ast_opt_high_priority);
2504 if (!is_child_of_nonroot && rungroup) {
2506 gr = getgrnam(rungroup);
2508 ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2511 if (setgid(gr->gr_gid)) {
2512 ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
2515 if (setgroups(0, NULL)) {
2516 ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2520 ast_verbose("Running as group '%s'\n", rungroup);
2523 if (!is_child_of_nonroot && runuser) {
2525 pw = getpwnam(runuser);
2527 ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2531 if (setgid(pw->pw_gid)) {
2532 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
2535 if (initgroups(pw->pw_name, pw->pw_gid)) {
2536 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2540 if (setuid(pw->pw_uid)) {
2541 ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
2544 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2546 ast_verbose("Running as user '%s'\n", runuser);
2549 #endif /* __CYGWIN__ */
2552 if (geteuid() && ast_opt_dump_core) {
2553 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
2554 ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
2563 if (ast_opt_console && !option_verbose)
2564 ast_verbose("[ Initializing Custom Configuration Options ]\n");
2565 /* custom config setup */
2566 register_config_cli();
2569 if (ast_opt_console) {
2570 if (el_hist == NULL || el == NULL)
2571 ast_el_initialize();
2573 if (!ast_strlen_zero(filename))
2574 ast_el_read_history(filename);
2577 if (ast_tryconnect()) {
2578 /* One is already running */
2579 if (ast_opt_remote) {
2581 ast_remotecontrol(xarg);
2582 quit_handler(0, 0, 0, 0);
2585 printf(term_quit());
2586 ast_remotecontrol(NULL);
2587 quit_handler(0, 0, 0, 0);
2590 ast_log(LOG_ERROR, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2591 printf(term_quit());
2594 } else if (ast_opt_remote || ast_opt_exec) {
2595 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
2596 printf(term_quit());
2599 /* Blindly write pid file since we couldn't connect */
2600 unlink(ast_config_AST_PID);
2601 f = fopen(ast_config_AST_PID, "w");
2603 fprintf(f, "%ld\n", (long)getpid());
2606 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2608 #if HAVE_WORKING_FORK
2609 if (ast_opt_always_fork || !ast_opt_no_fork) {
2611 ast_mainpid = getpid();
2612 /* Blindly re-write pid file since we are forking */
2613 unlink(ast_config_AST_PID);
2614 f = fopen(ast_config_AST_PID, "w");
2616 fprintf(f, "%ld\n", (long)ast_mainpid);
2619 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2623 /* Test recursive mutex locking. */
2624 if (test_for_thread_safety())
2625 ast_verbose("Warning! Asterisk is not thread safe.\n");
2629 sigaddset(&sigs, SIGHUP);
2630 sigaddset(&sigs, SIGTERM);
2631 sigaddset(&sigs, SIGINT);
2632 sigaddset(&sigs, SIGPIPE);
2633 sigaddset(&sigs, SIGWINCH);
2634 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2635 signal(SIGURG, urg_handler);
2636 signal(SIGINT, __quit_handler);
2637 signal(SIGTERM, __quit_handler);
2638 signal(SIGHUP, hup_handler);
2639 signal(SIGCHLD, child_handler);
2640 signal(SIGPIPE, SIG_IGN);
2642 /* ensure that the random number generators are seeded with a different value every time
2645 srand((unsigned int) getpid() + (unsigned int) time(NULL));
2646 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
2648 if (init_logger()) {
2649 printf(term_quit());
2652 if (load_modules(1)) {
2653 printf(term_quit());
2657 if (dnsmgr_init()) {
2658 printf(term_quit());
2664 ast_channels_init();
2666 if (init_manager()) {
2667 printf(term_quit());
2671 if (ast_cdr_engine_init()) {
2672 printf(term_quit());
2676 if (ast_device_state_engine_init()) {
2677 printf(term_quit());
2685 if (ast_image_init()) {
2686 printf(term_quit());
2690 if (ast_file_init()) {
2691 printf(term_quit());
2696 printf(term_quit());
2700 if (init_framer()) {
2701 printf(term_quit());
2706 printf(term_quit());
2710 if (ast_enum_init()) {
2711 printf(term_quit());
2715 if (load_modules(0)) {
2716 printf(term_quit());
2720 dnsmgr_start_refresh();
2722 /* We might have the option of showing a console, but for now just
2724 if (ast_opt_console && !option_verbose)
2725 ast_verbose(" ]\n");
2726 if (option_verbose || ast_opt_console)
2727 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2728 if (ast_opt_no_fork)
2729 consolethread = pthread_self();
2731 ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2732 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2734 #ifdef __AST_DEBUG_MALLOC
2738 time(&ast_startuptime);
2739 ast_cli_register_multiple(cli_asterisk, sizeof(cli_asterisk) / sizeof(struct ast_cli_entry));
2741 if (ast_opt_console) {
2742 /* Console stuff now... */
2743 /* Register our quit function */
2745 set_icon("Asterisk");
2746 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
2750 buf = (char *)el_gets(el, &num);
2752 if (buf[strlen(buf)-1] == '\n')
2753 buf[strlen(buf)-1] = '\0';
2755 consolehandler((char *)buf);
2757 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2758 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2759 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2761 fd = open("/dev/null", O_RDWR);
2763 dup2(fd, STDOUT_FILENO);
2764 dup2(fd, STDIN_FILENO);
2766 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2774 for (;;) { /* apparently needed for Mac OS X */
2775 struct pollfd p = { -1 /* no descriptor */, 0, 0 };