2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
22 * \mainpage Asterisk -- An Open Source Telephony Toolkit
24 * \par Developer Documentation for Asterisk
25 * This is the main developer documentation for Asterisk. It is
26 * generated by running "make progdocs".
27 * \par Additional documentation
29 * \arg \ref ConfigFiles
31 * \section copyright Copyright and author
33 * Copyright (C) 1999 - 2006, Digium, Inc.
34 * Asterisk is a trade mark registered by Digium, Inc.
36 * \author Mark Spencer <markster@digium.com>
37 * Also see \ref AstCREDITS
39 * \section license License
40 * See http://www.asterisk.org for more information about
41 * the Asterisk project. Please do not directly contact
42 * any of the maintainers of this project for assistance;
43 * the project provides a web site, mailing lists and IRC
44 * channels for your use.
46 * This program is free software, distributed under the terms of
47 * the GNU General Public License Version 2. See the LICENSE file
48 * at the top of the source tree.
50 * \verbinclude LICENSE
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
62 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
71 #include <sys/socket.h>
77 #include <sys/resource.h>
82 #include <sys/prctl.h>
87 #include <sys/prctl.h>
90 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
93 int daemon(int, int); /* defined in libresolv of all places */
97 #include "asterisk/logger.h"
98 #include "asterisk/options.h"
99 #include "asterisk/cli.h"
100 #include "asterisk/channel.h"
101 #include "asterisk/ulaw.h"
102 #include "asterisk/alaw.h"
103 #include "asterisk/callerid.h"
104 #include "asterisk/image.h"
105 #include "asterisk/tdd.h"
106 #include "asterisk/term.h"
107 #include "asterisk/manager.h"
108 #include "asterisk/cdr.h"
109 #include "asterisk/pbx.h"
110 #include "asterisk/enum.h"
111 #include "asterisk/rtp.h"
112 #include "asterisk/http.h"
113 #include "asterisk/udptl.h"
114 #include "asterisk/app.h"
115 #include "asterisk/lock.h"
116 #include "asterisk/utils.h"
117 #include "asterisk/file.h"
118 #include "asterisk/io.h"
119 #include "asterisk/lock.h"
120 #include "editline/histedit.h"
121 #include "asterisk/config.h"
122 #include "asterisk/version.h"
123 #include "asterisk/linkedlists.h"
124 #include "asterisk/devicestate.h"
126 #include "asterisk/doxyref.h" /* Doxygen documentation */
128 #include "defaults.h"
131 #define AF_LOCAL AF_UNIX
132 #define PF_LOCAL PF_UNIX
135 #define AST_MAX_CONNECTS 128
138 /*! \brief Welcome message when starting a CLI interface */
139 #define WELCOME_MESSAGE \
140 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
141 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
142 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
143 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
144 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
145 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
146 ast_verbose("=========================================================================\n")
148 /*! \defgroup main_options
149 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
150 the operating system command line when starting Asterisk
151 Some of them can be changed in the CLI
155 extern int ast_language_is_prefix
; /* XXX move to some header */
157 struct ast_flags ast_options
= { AST_DEFAULT_OPTIONS
};
159 int option_verbose
= 0; /*!< Verbosity level */
160 int option_debug
= 0; /*!< Debug level */
162 double option_maxload
= 0.0; /*!< Max load avg on system */
163 int option_maxcalls
= 0; /*!< Max number of active calls */
167 char record_cache_dir
[AST_CACHE_DIR_LEN
] = AST_TMP_DIR
;
168 char debug_filename
[AST_FILENAME_MAX
] = "";
170 static int ast_socket
= -1; /*!< UNIX Socket for allowing remote control */
171 static int ast_consock
= -1; /*!< UNIX Socket for controlling another asterisk */
174 int fd
; /*!< File descriptor */
175 int p
[2]; /*!< Pipe */
176 pthread_t t
; /*!< Thread of handler */
177 int mute
; /*!< Is the console muted for logs */
182 AST_LIST_ENTRY(ast_atexit
) list
;
185 static AST_LIST_HEAD_STATIC(atexits
, ast_atexit
);
187 time_t ast_startuptime
;
188 time_t ast_lastreloadtime
;
190 static History
*el_hist
= NULL
;
191 static EditLine
*el
= NULL
;
192 static char *remotehostname
;
194 struct console consoles
[AST_MAX_CONNECTS
];
196 char defaultlanguage
[MAX_LANGUAGE
] = DEFAULT_LANGUAGE
;
198 static int ast_el_add_history(char *);
199 static int ast_el_read_history(char *);
200 static int ast_el_write_history(char *);
202 char ast_config_AST_CONFIG_DIR
[PATH_MAX
];
203 char ast_config_AST_CONFIG_FILE
[PATH_MAX
];
204 char ast_config_AST_MODULE_DIR
[PATH_MAX
];
205 char ast_config_AST_SPOOL_DIR
[PATH_MAX
];
206 char ast_config_AST_MONITOR_DIR
[PATH_MAX
];
207 char ast_config_AST_VAR_DIR
[PATH_MAX
];
208 char ast_config_AST_DATA_DIR
[PATH_MAX
];
209 char ast_config_AST_LOG_DIR
[PATH_MAX
];
210 char ast_config_AST_AGI_DIR
[PATH_MAX
];
211 char ast_config_AST_DB
[PATH_MAX
];
212 char ast_config_AST_KEY_DIR
[PATH_MAX
];
213 char ast_config_AST_PID
[PATH_MAX
];
214 char ast_config_AST_SOCKET
[PATH_MAX
];
215 char ast_config_AST_RUN_DIR
[PATH_MAX
];
216 char ast_config_AST_RUN_USER
[PATH_MAX
];
217 char ast_config_AST_RUN_GROUP
[PATH_MAX
];
218 char ast_config_AST_CTL_PERMISSIONS
[PATH_MAX
];
219 char ast_config_AST_CTL_OWNER
[PATH_MAX
] = "\0";
220 char ast_config_AST_CTL_GROUP
[PATH_MAX
] = "\0";
221 char ast_config_AST_CTL
[PATH_MAX
] = "asterisk.ctl";
222 char ast_config_AST_SYSTEM_NAME
[20] = "";
224 extern const char *ast_build_hostname
;
225 extern const char *ast_build_kernel
;
226 extern const char *ast_build_machine
;
227 extern const char *ast_build_os
;
228 extern const char *ast_build_date
;
229 extern const char *ast_build_user
;
231 static char *_argv
[256];
232 static int shuttingdown
= 0;
233 static int restartnow
= 0;
234 static pthread_t consolethread
= AST_PTHREADT_NULL
;
236 static char randompool
[256];
238 #if !defined(LOW_MEMORY)
239 struct file_version
{
240 AST_LIST_ENTRY(file_version
) list
;
245 static AST_LIST_HEAD_STATIC(file_versions
, file_version
);
247 void ast_register_file_version(const char *file
, const char *version
)
249 struct file_version
*new;
251 size_t version_length
;
253 work
= ast_strdupa(version
);
254 work
= ast_strip(ast_strip_quoted(work
, "$", "$"));
255 version_length
= strlen(work
) + 1;
257 if (!(new = ast_calloc(1, sizeof(*new) + version_length
)))
261 new->version
= (char *) new + sizeof(*new);
262 memcpy(new->version
, work
, version_length
);
263 AST_LIST_LOCK(&file_versions
);
264 AST_LIST_INSERT_HEAD(&file_versions
, new, list
);
265 AST_LIST_UNLOCK(&file_versions
);
268 void ast_unregister_file_version(const char *file
)
270 struct file_version
*find
;
272 AST_LIST_LOCK(&file_versions
);
273 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions
, find
, list
) {
274 if (!strcasecmp(find
->file
, file
)) {
275 AST_LIST_REMOVE_CURRENT(&file_versions
, list
);
279 AST_LIST_TRAVERSE_SAFE_END
;
280 AST_LIST_UNLOCK(&file_versions
);
285 struct thread_list_t
{
286 AST_LIST_ENTRY(thread_list_t
) list
;
291 static AST_LIST_HEAD_STATIC(thread_list
, thread_list_t
);
293 static char show_threads_help
[] =
294 "Usage: show threads\n"
295 " List threads currently active in the system.\n";
297 void ast_register_thread(char *name
)
299 struct thread_list_t
*new = ast_calloc(1, sizeof(*new));
303 new->id
= pthread_self();
304 new->name
= name
; /* this was a copy already */
305 AST_LIST_LOCK(&thread_list
);
306 AST_LIST_INSERT_HEAD(&thread_list
, new, list
);
307 AST_LIST_UNLOCK(&thread_list
);
310 void ast_unregister_thread(void *id
)
312 struct thread_list_t
*x
;
314 AST_LIST_LOCK(&thread_list
);
315 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list
, x
, list
) {
316 if ((void *)x
->id
== id
) {
317 AST_LIST_REMOVE_CURRENT(&thread_list
, list
);
321 AST_LIST_TRAVERSE_SAFE_END
;
322 AST_LIST_UNLOCK(&thread_list
);
329 static int handle_show_threads(int fd
, int argc
, char *argv
[])
332 struct thread_list_t
*cur
;
334 AST_LIST_LOCK(&thread_list
);
335 AST_LIST_TRAVERSE(&thread_list
, cur
, list
) {
336 ast_cli(fd
, "%p %s\n", (void *)cur
->id
, cur
->name
);
339 AST_LIST_UNLOCK(&thread_list
);
340 ast_cli(fd
, "%d threads listed.\n", count
);
344 struct profile_entry
{
346 uint64_t scale
; /* if non-zero, values are scaled by this */
352 struct profile_data
{
355 struct profile_entry e
[0];
358 static struct profile_data
*prof_data
;
360 /*! \brief allocates a counter with a given name and scale.
361 * \return Returns the identifier of the counter.
363 int ast_add_profile(const char *name
, uint64_t scale
)
365 int l
= sizeof(struct profile_data
);
366 int n
= 10; /* default entries */
368 if (prof_data
== NULL
) {
369 prof_data
= ast_calloc(1, l
+ n
*sizeof(struct profile_entry
));
370 if (prof_data
== NULL
)
372 prof_data
->entries
= 0;
373 prof_data
->max_size
= n
;
375 if (prof_data
->entries
>= prof_data
->max_size
) {
377 n
= prof_data
->max_size
+ 20;
378 p
= ast_realloc(prof_data
, l
+ n
*sizeof(struct profile_entry
));
382 prof_data
->max_size
= n
;
384 n
= prof_data
->entries
++;
385 prof_data
->e
[n
].name
= ast_strdup(name
);
386 prof_data
->e
[n
].value
= 0;
387 prof_data
->e
[n
].events
= 0;
388 prof_data
->e
[n
].mark
= 0;
389 prof_data
->e
[n
].scale
= scale
;
393 int64_t ast_profile(int i
, int64_t delta
)
395 if (!prof_data
|| i
< 0 || i
> prof_data
->entries
) /* invalid index */
397 if (prof_data
->e
[i
].scale
> 1)
398 delta
/= prof_data
->e
[i
].scale
;
399 prof_data
->e
[i
].value
+= delta
;
400 prof_data
->e
[i
].events
++;
401 return prof_data
->e
[i
].value
;
404 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
405 #if defined(__FreeBSD__)
406 #include <machine/cpufunc.h>
408 static __inline u_int64_t
413 __asm
__volatile(".byte 0x0f, 0x31" : "=A" (rv
));
417 #else /* supply a dummy function on other platforms */
418 static __inline u_int64_t
425 int64_t ast_mark(int i
, int startstop
)
427 if (!prof_data
|| i
< 0 || i
> prof_data
->entries
) /* invalid index */
430 prof_data
->e
[i
].mark
= rdtsc();
432 prof_data
->e
[i
].mark
= (rdtsc() - prof_data
->e
[i
].mark
);
433 if (prof_data
->e
[i
].scale
> 1)
434 prof_data
->e
[i
].mark
/= prof_data
->e
[i
].scale
;
435 prof_data
->e
[i
].value
+= prof_data
->e
[i
].mark
;
436 prof_data
->e
[i
].events
++;
438 return prof_data
->e
[i
].mark
;
441 static int handle_show_profile(int fd
, int argc
, char *argv
[])
446 if (prof_data
== NULL
)
450 max
= prof_data
->entries
;
451 if (argc
>= 3) { /* specific entries */
452 if (isdigit(argv
[2][0])) {
454 if (argc
== 4 && strcmp(argv
[3], "-"))
459 if (max
> prof_data
->entries
)
460 max
= prof_data
->entries
;
461 if (!strcmp(argv
[0], "clear")) {
462 for (i
= min
; i
< max
; i
++) {
463 if (!search
|| strstr(prof_data
->e
[i
].name
, search
)) {
464 prof_data
->e
[i
].value
= 0;
465 prof_data
->e
[i
].events
= 0;
470 ast_cli(fd
, "profile values (%d, allocated %d)\n-------------------\n",
471 prof_data
->entries
, prof_data
->max_size
);
472 for (i
= min
; i
< max
; i
++) {
473 struct profile_entry
*e
= &prof_data
->e
[i
];
474 if (!search
|| strstr(prof_data
->e
[i
].name
, search
))
475 ast_cli(fd
, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
478 (long)e
->events
, (long long)e
->value
,
479 (long long)(e
->events
? e
->value
/ e
->events
: e
->value
),
485 static char show_version_files_help
[] =
486 "Usage: show version files [like <pattern>]\n"
487 " Shows the revision numbers of the files used to build this copy of Asterisk.\n"
488 " Optional regular expression pattern is used to filter the file list.\n";
490 /*! \brief CLI command to list module versions */
491 static int handle_show_version_files(int fd
, int argc
, char *argv
[])
493 #define FORMAT "%-25.25s %-40.40s\n"
494 struct file_version
*iterator
;
502 if (!strcasecmp(argv
[3], "like")) {
503 if (regcomp(®exbuf
, argv
[4], REG_EXTENDED
| REG_NOSUB
))
504 return RESULT_SHOWUSAGE
;
507 return RESULT_SHOWUSAGE
;
515 return RESULT_SHOWUSAGE
;
518 ast_cli(fd
, FORMAT
, "File", "Revision");
519 ast_cli(fd
, FORMAT
, "----", "--------");
520 AST_LIST_LOCK(&file_versions
);
521 AST_LIST_TRAVERSE(&file_versions
, iterator
, list
) {
522 if (havename
&& strcasecmp(iterator
->file
, argv
[3]))
525 if (havepattern
&& regexec(®exbuf
, iterator
->file
, 0, NULL
, 0))
528 ast_cli(fd
, FORMAT
, iterator
->file
, iterator
->version
);
533 AST_LIST_UNLOCK(&file_versions
);
535 ast_cli(fd
, "%d files listed.\n", count_files
);
541 return RESULT_SUCCESS
;
545 static char *complete_show_version_files(const char *line
, const char *word
, int pos
, int state
)
547 struct file_version
*find
;
550 int matchlen
= strlen(word
);
555 AST_LIST_LOCK(&file_versions
);
556 AST_LIST_TRAVERSE(&file_versions
, find
, list
) {
557 if (!strncasecmp(word
, find
->file
, matchlen
) && ++which
> state
) {
558 ret
= ast_strdup(find
->file
);
562 AST_LIST_UNLOCK(&file_versions
);
566 #endif /* ! LOW_MEMORY */
568 int ast_register_atexit(void (*func
)(void))
571 struct ast_atexit
*ae
;
572 ast_unregister_atexit(func
);
573 AST_LIST_LOCK(&atexits
);
574 if ((ae
= ast_calloc(1, sizeof(*ae
)))) {
575 AST_LIST_INSERT_HEAD(&atexits
, ae
, list
);
579 AST_LIST_UNLOCK(&atexits
);
583 void ast_unregister_atexit(void (*func
)(void))
585 struct ast_atexit
*ae
;
586 AST_LIST_LOCK(&atexits
);
587 AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits
, ae
, list
) {
588 if (ae
->func
== func
) {
589 AST_LIST_REMOVE_CURRENT(&atexits
, list
);
593 AST_LIST_TRAVERSE_SAFE_END
594 AST_LIST_UNLOCK(&atexits
);
597 static int fdprint(int fd
, const char *s
)
599 return write(fd
, s
, strlen(s
) + 1);
602 /*! \brief NULL handler so we can collect the child exit status */
603 static void null_sig_handler(int signal
)
608 AST_MUTEX_DEFINE_STATIC(safe_system_lock
);
609 /*! \brief Keep track of how many threads are currently trying to wait*() on
611 static unsigned int safe_system_level
= 0;
612 static void *safe_system_prev_handler
;
614 void ast_replace_sigchld(void)
618 ast_mutex_lock(&safe_system_lock
);
619 level
= safe_system_level
++;
621 /* only replace the handler if it has not already been done */
623 safe_system_prev_handler
= signal(SIGCHLD
, null_sig_handler
);
625 ast_mutex_unlock(&safe_system_lock
);
628 void ast_unreplace_sigchld(void)
632 ast_mutex_lock(&safe_system_lock
);
633 level
= --safe_system_level
;
635 /* only restore the handler if we are the last one */
637 signal(SIGCHLD
, safe_system_prev_handler
);
639 ast_mutex_unlock(&safe_system_lock
);
642 int ast_safe_system(const char *s
)
647 struct rusage rusage
;
650 ast_replace_sigchld();
655 if (ast_opt_high_priority
)
657 /* Close file descriptors and launch system command */
658 for (x
= STDERR_FILENO
+ 1; x
< 4096; x
++)
660 execl("/bin/sh", "/bin/sh", "-c", s
, (char *) NULL
);
662 } else if (pid
> 0) {
664 res
= wait4(pid
, &status
, 0, &rusage
);
666 res
= WIFEXITED(status
) ? WEXITSTATUS(status
) : -1;
668 } else if (errno
!= EINTR
)
672 ast_log(LOG_WARNING
, "Fork failed: %s\n", strerror(errno
));
676 ast_unreplace_sigchld();
682 * \brief mute or unmute a console from logging
684 void ast_console_toggle_mute(int fd
) {
686 for (x
= 0;x
< AST_MAX_CONNECTS
; x
++) {
687 if (fd
== consoles
[x
].fd
) {
688 if (consoles
[x
].mute
) {
689 consoles
[x
].mute
= 0;
690 ast_cli(fd
, "Console is not muted anymore.\n");
692 consoles
[x
].mute
= 1;
693 ast_cli(fd
, "Console is muted.\n");
698 ast_cli(fd
, "Couldn't find remote console.\n");
702 * \brief log the string to all attached console clients
704 static void ast_network_puts_mutable(const char *string
)
707 for (x
= 0;x
< AST_MAX_CONNECTS
; x
++) {
708 if (consoles
[x
].mute
)
710 if (consoles
[x
].fd
> -1)
711 fdprint(consoles
[x
].p
[1], string
);
716 * \brief log the string to the console, and all attached
719 void ast_console_puts_mutable(const char *string
)
721 fputs(string
, stdout
);
723 ast_network_puts_mutable(string
);
727 * \brief write the string to all attached console clients
729 static void ast_network_puts(const char *string
)
732 for (x
=0; x
< AST_MAX_CONNECTS
; x
++) {
733 if (consoles
[x
].fd
> -1)
734 fdprint(consoles
[x
].p
[1], string
);
739 * write the string to the console, and all attached
742 void ast_console_puts(const char *string
)
744 fputs(string
, stdout
);
746 ast_network_puts(string
);
749 static void network_verboser(const char *s
, int pos
, int replace
, int complete
)
754 if ((t
= alloca(strlen(s
) + 2))) {
755 sprintf(t
, "\r%s", s
);
757 ast_network_puts_mutable(t
);
759 ast_log(LOG_ERROR
, "Out of memory\n");
760 ast_network_puts_mutable(s
);
764 ast_network_puts_mutable(s
);
768 static pthread_t lthread
;
770 static void *netconsole(void *vconsole
)
772 struct console
*con
= vconsole
;
773 char hostname
[MAXHOSTNAMELEN
] = "";
776 struct pollfd fds
[2];
778 if (gethostname(hostname
, sizeof(hostname
)-1))
779 ast_copy_string(hostname
, "<Unknown>", sizeof(hostname
));
780 snprintf(tmp
, sizeof(tmp
), "%s/%ld/%s\n", hostname
, (long)ast_mainpid
, ASTERISK_VERSION
);
781 fdprint(con
->fd
, tmp
);
784 fds
[0].events
= POLLIN
;
786 fds
[1].fd
= con
->p
[0];
787 fds
[1].events
= POLLIN
;
790 res
= poll(fds
, 2, -1);
793 ast_log(LOG_WARNING
, "poll returned < 0: %s\n", strerror(errno
));
796 if (fds
[0].revents
) {
797 res
= read(con
->fd
, tmp
, sizeof(tmp
));
802 ast_cli_command(con
->fd
, tmp
);
804 if (fds
[1].revents
) {
805 res
= read(con
->p
[0], tmp
, sizeof(tmp
));
807 ast_log(LOG_ERROR
, "read returned %d\n", res
);
810 res
= write(con
->fd
, tmp
, res
);
815 if (option_verbose
> 2)
816 ast_verbose(VERBOSE_PREFIX_3
"Remote UNIX connection disconnected\n");
825 static void *listener(void *unused
)
827 struct sockaddr_un sunaddr
;
832 struct pollfd fds
[1];
834 pthread_attr_init(&attr
);
835 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
839 fds
[0].fd
= ast_socket
;
840 fds
[0].events
= POLLIN
;
841 s
= poll(fds
, 1, -1);
842 pthread_testcancel();
845 ast_log(LOG_WARNING
, "poll returned error: %s\n", strerror(errno
));
848 len
= sizeof(sunaddr
);
849 s
= accept(ast_socket
, (struct sockaddr
*)&sunaddr
, &len
);
852 ast_log(LOG_WARNING
, "Accept returned %d: %s\n", s
, strerror(errno
));
854 for (x
= 0; x
< AST_MAX_CONNECTS
; x
++) {
855 if (consoles
[x
].fd
< 0) {
856 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, consoles
[x
].p
)) {
857 ast_log(LOG_ERROR
, "Unable to create pipe: %s\n", strerror(errno
));
859 fdprint(s
, "Server failed to create pipe\n");
863 flags
= fcntl(consoles
[x
].p
[1], F_GETFL
);
864 fcntl(consoles
[x
].p
[1], F_SETFL
, flags
| O_NONBLOCK
);
866 consoles
[x
].mute
= ast_opt_mute
;
867 if (ast_pthread_create(&consoles
[x
].t
, &attr
, netconsole
, &consoles
[x
])) {
868 ast_log(LOG_ERROR
, "Unable to spawn thread to handle connection: %s\n", strerror(errno
));
869 close(consoles
[x
].p
[0]);
870 close(consoles
[x
].p
[1]);
872 fdprint(s
, "Server failed to spawn thread\n");
878 if (x
>= AST_MAX_CONNECTS
) {
879 fdprint(s
, "No more connections allowed\n");
880 ast_log(LOG_WARNING
, "No more connections allowed\n");
882 } else if (consoles
[x
].fd
> -1) {
883 if (option_verbose
> 2)
884 ast_verbose(VERBOSE_PREFIX_3
"Remote UNIX connection\n");
891 static int ast_makesocket(void)
893 struct sockaddr_un sunaddr
;
899 for (x
= 0; x
< AST_MAX_CONNECTS
; x
++)
901 unlink(ast_config_AST_SOCKET
);
902 ast_socket
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
903 if (ast_socket
< 0) {
904 ast_log(LOG_WARNING
, "Unable to create control socket: %s\n", strerror(errno
));
907 memset(&sunaddr
, 0, sizeof(sunaddr
));
908 sunaddr
.sun_family
= AF_LOCAL
;
909 ast_copy_string(sunaddr
.sun_path
, ast_config_AST_SOCKET
, sizeof(sunaddr
.sun_path
));
910 res
= bind(ast_socket
, (struct sockaddr
*)&sunaddr
, sizeof(sunaddr
));
912 ast_log(LOG_WARNING
, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET
, strerror(errno
));
917 res
= listen(ast_socket
, 2);
919 ast_log(LOG_WARNING
, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET
, strerror(errno
));
924 ast_register_verbose(network_verboser
);
925 ast_pthread_create(<hread
, NULL
, listener
, NULL
);
927 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER
)) {
929 if ((pw
= getpwnam(ast_config_AST_CTL_OWNER
)) == NULL
) {
930 ast_log(LOG_WARNING
, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER
);
936 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP
)) {
938 if ((grp
= getgrnam(ast_config_AST_CTL_GROUP
)) == NULL
) {
939 ast_log(LOG_WARNING
, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP
);
945 if (chown(ast_config_AST_SOCKET
, uid
, gid
) < 0)
946 ast_log(LOG_WARNING
, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET
, strerror(errno
));
948 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS
)) {
951 sscanf(ast_config_AST_CTL_PERMISSIONS
, "%o", &p1
);
953 if ((chmod(ast_config_AST_SOCKET
, p
)) < 0)
954 ast_log(LOG_WARNING
, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET
, strerror(errno
));
960 static int ast_tryconnect(void)
962 struct sockaddr_un sunaddr
;
964 ast_consock
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
965 if (ast_consock
< 0) {
966 ast_log(LOG_WARNING
, "Unable to create socket: %s\n", strerror(errno
));
969 memset(&sunaddr
, 0, sizeof(sunaddr
));
970 sunaddr
.sun_family
= AF_LOCAL
;
971 ast_copy_string(sunaddr
.sun_path
, (char *)ast_config_AST_SOCKET
, sizeof(sunaddr
.sun_path
));
972 res
= connect(ast_consock
, (struct sockaddr
*)&sunaddr
, sizeof(sunaddr
));
981 /*! \brief Urgent handler
983 Called by soft_hangup to interrupt the poll, read, or other
984 system call. We don't actually need to do anything though.
985 Remember: Cannot EVER ast_log from within a signal handler
987 static void urg_handler(int num
)
989 signal(num
, urg_handler
);
993 static void hup_handler(int num
)
995 if (option_verbose
> 1)
996 printf("Received HUP signal -- Reloading configs\n");
998 execvp(_argv
[0], _argv
);
999 /* XXX This could deadlock XXX */
1000 ast_module_reload(NULL
);
1001 signal(num
, hup_handler
);
1004 static void child_handler(int sig
)
1006 /* Must not ever ast_log or ast_verbose within signal handler */
1010 * Reap all dead children -- not just one
1012 for (n
= 0; wait4(-1, &status
, WNOHANG
, NULL
) > 0; n
++)
1014 if (n
== 0 && option_debug
)
1015 printf("Huh? Child handler, but nobody there?\n");
1016 signal(sig
, child_handler
);
1019 /*! \brief Set an X-term or screen title */
1020 static void set_title(char *text
)
1022 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1023 fprintf(stdout
, "\033]2;%s\007", text
);
1026 static void set_icon(char *text
)
1028 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1029 fprintf(stdout
, "\033]1;%s\007", text
);
1032 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1033 else. If your PBX has heavy activity on it, this is a good thing. */
1034 int ast_set_priority(int pri
)
1036 struct sched_param sched
;
1037 memset(&sched
, 0, sizeof(sched
));
1040 sched
.sched_priority
= 10;
1041 if (sched_setscheduler(0, SCHED_RR
, &sched
)) {
1042 ast_log(LOG_WARNING
, "Unable to set high priority\n");
1046 ast_verbose("Set to realtime thread\n");
1048 sched
.sched_priority
= 0;
1049 if (sched_setscheduler(0, SCHED_OTHER
, &sched
)) {
1050 ast_log(LOG_WARNING
, "Unable to set normal priority\n");
1056 if (setpriority(PRIO_PROCESS
, 0, -10) == -1) {
1057 ast_log(LOG_WARNING
, "Unable to set high priority\n");
1061 ast_verbose("Set to high priority\n");
1063 if (setpriority(PRIO_PROCESS
, 0, 0) == -1) {
1064 ast_log(LOG_WARNING
, "Unable to set normal priority\n");
1072 static void ast_run_atexits(void)
1074 struct ast_atexit
*ae
;
1075 AST_LIST_LOCK(&atexits
);
1076 AST_LIST_TRAVERSE(&atexits
, ae
, list
) {
1080 AST_LIST_UNLOCK(&atexits
);
1083 static void quit_handler(int num
, int nice
, int safeshutdown
, int restart
)
1085 char filename
[80] = "";
1088 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1089 ast_cdr_engine_term();
1093 /* Begin shutdown routine, hanging up active channels */
1094 ast_begin_shutdown(1);
1095 if (option_verbose
&& ast_opt_console
)
1096 ast_verbose("Beginning asterisk %s....\n", restart
? "restart" : "shutdown");
1100 /* Wait up to 15 seconds for all channels to go away */
1103 if (!ast_active_channels())
1107 /* Sleep 1/10 of a second */
1112 ast_begin_shutdown(0);
1113 if (option_verbose
&& ast_opt_console
)
1114 ast_verbose("Waiting for inactivity to perform %s...\n", restart
? "restart" : "halt");
1116 if (!ast_active_channels())
1124 if (!shuttingdown
) {
1125 if (option_verbose
&& ast_opt_console
)
1126 ast_verbose("Asterisk %s cancelled.\n", restart
? "restart" : "shutdown");
1130 if (ast_opt_console
|| ast_opt_remote
) {
1132 snprintf(filename
, sizeof(filename
), "%s/.asterisk_history", getenv("HOME"));
1133 if (!ast_strlen_zero(filename
))
1134 ast_el_write_history(filename
);
1137 if (el_hist
!= NULL
)
1138 history_end(el_hist
);
1141 ast_verbose("Executing last minute cleanups\n");
1143 /* Called on exit */
1144 if (option_verbose
&& ast_opt_console
)
1145 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num
);
1146 else if (option_debug
)
1147 ast_log(LOG_DEBUG
, "Asterisk ending (%d).\n", num
);
1148 manager_event(EVENT_FLAG_SYSTEM
, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart
? "True" : "False");
1149 if (ast_socket
> -1) {
1150 pthread_cancel(lthread
);
1153 unlink(ast_config_AST_SOCKET
);
1155 if (ast_consock
> -1)
1157 if (!ast_opt_remote
)
1158 unlink(ast_config_AST_PID
);
1159 printf(term_quit());
1161 if (option_verbose
|| ast_opt_console
)
1162 ast_verbose("Preparing for Asterisk restart...\n");
1163 /* Mark all FD's for closing on exec */
1164 for (x
=3; x
< 32768; x
++) {
1165 fcntl(x
, F_SETFD
, FD_CLOEXEC
);
1167 if (option_verbose
|| ast_opt_console
)
1168 ast_verbose("Restarting Asterisk NOW...\n");
1174 /* If there is a consolethread running send it a SIGHUP
1175 so it can execvp, otherwise we can do it ourselves */
1176 if ((consolethread
!= AST_PTHREADT_NULL
) && (consolethread
!= pthread_self())) {
1177 pthread_kill(consolethread
, SIGHUP
);
1178 /* Give the signal handler some time to complete */
1181 execvp(_argv
[0], _argv
);
1190 static void __quit_handler(int num
)
1192 quit_handler(num
, 0, 1, 0);
1195 static const char *fix_header(char *outbuf
, int maxout
, const char *s
, char *cmp
)
1198 if (!strncmp(s
, cmp
, strlen(cmp
))) {
1199 c
= s
+ strlen(cmp
);
1200 term_color(outbuf
, cmp
, COLOR_GRAY
, 0, maxout
);
1206 static void console_verboser(const char *s
, int pos
, int replace
, int complete
)
1209 const char *c
= NULL
;
1210 /* Return to the beginning of the line */
1212 fprintf(stdout
, "\r");
1213 if ((c
= fix_header(tmp
, sizeof(tmp
), s
, VERBOSE_PREFIX_4
)) ||
1214 (c
= fix_header(tmp
, sizeof(tmp
), s
, VERBOSE_PREFIX_3
)) ||
1215 (c
= fix_header(tmp
, sizeof(tmp
), s
, VERBOSE_PREFIX_2
)) ||
1216 (c
= fix_header(tmp
, sizeof(tmp
), s
, VERBOSE_PREFIX_1
)))
1220 fputs(c
+ pos
,stdout
);
1222 fputs(s
+ pos
,stdout
);
1225 /* Wake up a poll()ing console */
1226 if (ast_opt_console
&& consolethread
!= AST_PTHREADT_NULL
)
1227 pthread_kill(consolethread
, SIGURG
);
1231 static int ast_all_zeros(char *s
)
1241 static void consolehandler(char *s
)
1246 /* Called when readline data is available */
1247 if (!ast_all_zeros(s
))
1248 ast_el_add_history(s
);
1249 /* The real handler for bang */
1252 ast_safe_system(s
+1);
1254 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1256 ast_cli_command(STDOUT_FILENO
, s
);
1259 static int remoteconsolehandler(char *s
)
1263 /* Called when readline data is available */
1264 if (!ast_all_zeros(s
))
1265 ast_el_add_history(s
);
1266 /* The real handler for bang */
1269 ast_safe_system(s
+1);
1271 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1274 if ((strncasecmp(s
, "quit", 4) == 0 || strncasecmp(s
, "exit", 4) == 0) &&
1275 (s
[4] == '\0' || isspace(s
[4]))) {
1276 quit_handler(0, 0, 0, 0);
1283 static char abort_halt_help
[] =
1284 "Usage: abort shutdown\n"
1285 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1286 " call operations.\n";
1288 static char shutdown_now_help
[] =
1290 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1292 static char shutdown_gracefully_help
[] =
1293 "Usage: stop gracefully\n"
1294 " Causes Asterisk to not accept new calls, and exit when all\n"
1295 " active calls have terminated normally.\n";
1297 static char shutdown_when_convenient_help
[] =
1298 "Usage: stop when convenient\n"
1299 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1301 static char restart_now_help
[] =
1302 "Usage: restart now\n"
1303 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1306 static char restart_gracefully_help
[] =
1307 "Usage: restart gracefully\n"
1308 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1309 " restart when all active calls have ended.\n";
1311 static char restart_when_convenient_help
[] =
1312 "Usage: restart when convenient\n"
1313 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1315 static char bang_help
[] =
1316 "Usage: !<command>\n"
1317 " Executes a given shell command\n";
1319 static char show_warranty_help
[] =
1320 "Usage: show warranty\n"
1321 " Shows the warranty (if any) for this copy of Asterisk.\n";
1323 static char show_license_help
[] =
1324 "Usage: show license\n"
1325 " Shows the license(s) for this copy of Asterisk.\n";
1327 static char version_help
[] =
1328 "Usage: show version\n"
1329 " Shows Asterisk version information.\n";
1331 static int handle_version(int fd
, int argc
, char *argv
[])
1334 return RESULT_SHOWUSAGE
;
1335 ast_cli(fd
, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1336 ASTERISK_VERSION
, ast_build_user
, ast_build_hostname
,
1337 ast_build_machine
, ast_build_os
, ast_build_date
);
1338 return RESULT_SUCCESS
;
1342 static int handle_quit(int fd
, int argc
, char *argv
[])
1345 return RESULT_SHOWUSAGE
;
1346 quit_handler(0, 0, 1, 0);
1347 return RESULT_SUCCESS
;
1351 static int handle_shutdown_now(int fd
, int argc
, char *argv
[])
1354 return RESULT_SHOWUSAGE
;
1355 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1356 return RESULT_SUCCESS
;
1359 static int handle_shutdown_gracefully(int fd
, int argc
, char *argv
[])
1362 return RESULT_SHOWUSAGE
;
1363 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1364 return RESULT_SUCCESS
;
1367 static int handle_shutdown_when_convenient(int fd
, int argc
, char *argv
[])
1370 return RESULT_SHOWUSAGE
;
1371 ast_cli(fd
, "Waiting for inactivity to perform halt\n");
1372 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1373 return RESULT_SUCCESS
;
1376 static int handle_restart_now(int fd
, int argc
, char *argv
[])
1379 return RESULT_SHOWUSAGE
;
1380 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1381 return RESULT_SUCCESS
;
1384 static int handle_restart_gracefully(int fd
, int argc
, char *argv
[])
1387 return RESULT_SHOWUSAGE
;
1388 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1389 return RESULT_SUCCESS
;
1392 static int handle_restart_when_convenient(int fd
, int argc
, char *argv
[])
1395 return RESULT_SHOWUSAGE
;
1396 ast_cli(fd
, "Waiting for inactivity to perform restart\n");
1397 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1398 return RESULT_SUCCESS
;
1401 static int handle_abort_halt(int fd
, int argc
, char *argv
[])
1404 return RESULT_SHOWUSAGE
;
1405 ast_cancel_shutdown();
1407 return RESULT_SUCCESS
;
1410 static int handle_bang(int fd
, int argc
, char *argv
[])
1412 return RESULT_SUCCESS
;
1414 static const char *warranty_lines
[] = {
1418 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1419 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1420 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1421 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1422 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1423 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1424 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1425 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1426 "REPAIR OR CORRECTION.\n",
1428 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1429 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1430 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1431 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1432 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1433 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1434 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1435 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1436 "POSSIBILITY OF SUCH DAMAGES.\n",
1439 static int show_warranty(int fd
, int argc
, char *argv
[])
1443 for (x
= 0; x
< sizeof(warranty_lines
) / sizeof(warranty_lines
[0]); x
++)
1444 ast_cli(fd
, (char *) warranty_lines
[x
]);
1446 return RESULT_SUCCESS
;
1449 static const char *license_lines
[] = {
1451 "This program is free software; you can redistribute it and/or modify\n",
1452 "it under the terms of the GNU General Public License version 2 as\n",
1453 "published by the Free Software Foundation.\n",
1455 "This program also contains components licensed under other licenses.\n",
1458 "This program is distributed in the hope that it will be useful,\n",
1459 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1460 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1461 "GNU General Public License for more details.\n",
1463 "You should have received a copy of the GNU General Public License\n",
1464 "along with this program; if not, write to the Free Software\n",
1465 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1468 static int show_license(int fd
, int argc
, char *argv
[])
1472 for (x
= 0; x
< sizeof(license_lines
) / sizeof(license_lines
[0]); x
++)
1473 ast_cli(fd
, (char *) license_lines
[x
]);
1475 return RESULT_SUCCESS
;
1478 #define ASTERISK_PROMPT "*CLI> "
1480 #define ASTERISK_PROMPT2 "%s*CLI> "
1482 static struct ast_cli_entry core_cli
[] = {
1483 { { "abort", "halt", NULL
}, handle_abort_halt
,
1484 "Cancel a running halt", abort_halt_help
},
1485 { { "stop", "now", NULL
}, handle_shutdown_now
,
1486 "Shut down Asterisk immediately", shutdown_now_help
},
1487 { { "stop", "gracefully", NULL
}, handle_shutdown_gracefully
,
1488 "Gracefully shut down Asterisk", shutdown_gracefully_help
},
1489 { { "stop", "when","convenient", NULL
}, handle_shutdown_when_convenient
,
1490 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help
},
1491 { { "restart", "now", NULL
}, handle_restart_now
,
1492 "Restart Asterisk immediately", restart_now_help
},
1493 { { "restart", "gracefully", NULL
}, handle_restart_gracefully
,
1494 "Restart Asterisk gracefully", restart_gracefully_help
},
1495 { { "restart", "when", "convenient", NULL
}, handle_restart_when_convenient
,
1496 "Restart Asterisk at empty call volume", restart_when_convenient_help
},
1497 { { "show", "warranty", NULL
}, show_warranty
,
1498 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help
},
1499 { { "show", "license", NULL
}, show_license
,
1500 "Show the license(s) for this copy of Asterisk", show_license_help
},
1501 { { "show", "version", NULL
}, handle_version
,
1502 "Display version info", version_help
},
1503 { { "!", NULL
}, handle_bang
,
1504 "Execute a shell command", bang_help
},
1505 #if !defined(LOW_MEMORY)
1506 { { "show", "version", "files", NULL
}, handle_show_version_files
,
1507 "Show versions of files used to build Asterisk", show_version_files_help
, complete_show_version_files
},
1508 { { "show", "threads", NULL
}, handle_show_threads
,
1509 "Show running threads", show_threads_help
, NULL
},
1510 { { "show", "profile", NULL
}, handle_show_profile
,
1511 "Show profiling info"},
1512 { { "clear", "profile", NULL
}, handle_show_profile
,
1513 "Clear profiling info"},
1514 #endif /* ! LOW_MEMORY */
1517 static int ast_el_read_char(EditLine
*el
, char *cp
)
1521 struct pollfd fds
[2];
1528 fds
[0].fd
= ast_consock
;
1529 fds
[0].events
= POLLIN
;
1530 if (!ast_opt_exec
) {
1531 fds
[1].fd
= STDIN_FILENO
;
1532 fds
[1].events
= POLLIN
;
1535 res
= poll(fds
, max
, -1);
1539 ast_log(LOG_ERROR
, "poll failed: %s\n", strerror(errno
));
1543 if (!ast_opt_exec
&& fds
[1].revents
) {
1544 num_read
= read(STDIN_FILENO
, cp
, 1);
1550 if (fds
[0].revents
) {
1551 res
= read(ast_consock
, buf
, sizeof(buf
) - 1);
1552 /* if the remote side disappears exit */
1554 fprintf(stderr
, "\nDisconnected from Asterisk server\n");
1555 if (!ast_opt_reconnect
) {
1556 quit_handler(0, 0, 0, 0);
1559 int reconnects_per_second
= 20;
1560 fprintf(stderr
, "Attempting to reconnect for 30 seconds\n");
1561 for (tries
=0; tries
< 30 * reconnects_per_second
; tries
++) {
1562 if (ast_tryconnect()) {
1563 fprintf(stderr
, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second
* tries
);
1564 printf(term_quit());
1568 usleep(1000000 / reconnects_per_second
);
1571 if (tries
>= 30 * reconnects_per_second
) {
1572 fprintf(stderr
, "Failed to reconnect for 30 seconds. Quitting.\n");
1573 quit_handler(0, 0, 0, 0);
1580 if (!ast_opt_exec
&& !lastpos
)
1581 write(STDOUT_FILENO
, "\r", 1);
1582 write(STDOUT_FILENO
, buf
, res
);
1583 if ((buf
[res
-1] == '\n') || (buf
[res
-2] == '\n')) {
1596 static char *cli_prompt(EditLine
*el
)
1598 static char prompt
[200];
1603 if ((pfmt
= getenv("ASTERISK_PROMPT"))) {
1604 char *t
= pfmt
, *p
= prompt
;
1605 memset(prompt
, 0, sizeof(prompt
));
1606 while (*t
!= '\0' && *p
< sizeof(prompt
)) {
1608 char hostname
[MAXHOSTNAMELEN
]="";
1615 int fgcolor
= COLOR_WHITE
, bgcolor
= COLOR_BLACK
;
1619 case 'C': /* color */
1621 if (sscanf(t
, "%d;%d%n", &fgcolor
, &bgcolor
, &i
) == 2) {
1622 strncat(p
, term_color_code(term_code
, fgcolor
, bgcolor
, sizeof(term_code
)),sizeof(prompt
) - strlen(prompt
) - 1);
1624 } else if (sscanf(t
, "%d%n", &fgcolor
, &i
) == 1) {
1625 strncat(p
, term_color_code(term_code
, fgcolor
, 0, sizeof(term_code
)),sizeof(prompt
) - strlen(prompt
) - 1);
1629 /* If the color has been reset correctly, then there's no need to reset it later */
1630 if ((fgcolor
== COLOR_WHITE
) && (bgcolor
== COLOR_BLACK
)) {
1636 case 'd': /* date */
1637 memset(&tm
, 0, sizeof(tm
));
1639 if (localtime_r(&ts
, &tm
)) {
1640 strftime(p
, sizeof(prompt
) - strlen(prompt
), "%Y-%m-%d", &tm
);
1643 case 'h': /* hostname */
1644 if (!gethostname(hostname
, sizeof(hostname
) - 1)) {
1645 strncat(p
, hostname
, sizeof(prompt
) - strlen(prompt
) - 1);
1647 strncat(p
, "localhost", sizeof(prompt
) - strlen(prompt
) - 1);
1650 case 'H': /* short hostname */
1651 if (!gethostname(hostname
, sizeof(hostname
) - 1)) {
1652 for (i
= 0; i
< sizeof(hostname
); i
++) {
1653 if (hostname
[i
] == '.') {
1658 strncat(p
, hostname
, sizeof(prompt
) - strlen(prompt
) - 1);
1660 strncat(p
, "localhost", sizeof(prompt
) - strlen(prompt
) - 1);
1664 case 'l': /* load avg */
1666 if ((LOADAVG
= fopen("/proc/loadavg", "r"))) {
1667 float avg1
, avg2
, avg3
;
1668 int actproc
, totproc
, npid
, which
;
1669 fscanf(LOADAVG
, "%f %f %f %d/%d %d",
1670 &avg1
, &avg2
, &avg3
, &actproc
, &totproc
, &npid
);
1671 if (sscanf(t
, "%d", &which
) == 1) {
1674 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%.2f", avg1
);
1677 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%.2f", avg2
);
1680 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%.2f", avg3
);
1683 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%d/%d", actproc
, totproc
);
1686 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%d", npid
);
1693 case 's': /* Asterisk system name (from asterisk.conf) */
1694 strncat(p
, ast_config_AST_SYSTEM_NAME
, sizeof(prompt
) - strlen(prompt
) - 1);
1696 case 't': /* time */
1697 memset(&tm
, 0, sizeof(tm
));
1699 if (localtime_r(&ts
, &tm
)) {
1700 strftime(p
, sizeof(prompt
) - strlen(prompt
), "%H:%M:%S", &tm
);
1703 case '#': /* process console or remote? */
1704 if (!ast_opt_remote
) {
1705 strncat(p
, "#", sizeof(prompt
) - strlen(prompt
) - 1);
1707 strncat(p
, ">", sizeof(prompt
) - strlen(prompt
) - 1);
1710 case '%': /* literal % */
1711 strncat(p
, "%", sizeof(prompt
) - strlen(prompt
) - 1);
1713 case '\0': /* % is last character - prevent bug */
1717 while (*p
!= '\0') {
1728 /* Force colors back to normal at end */
1729 term_color_code(term_code
, COLOR_WHITE
, COLOR_BLACK
, sizeof(term_code
));
1730 if (strlen(term_code
) > sizeof(prompt
) - strlen(prompt
)) {
1731 strncat(prompt
+ sizeof(prompt
) - strlen(term_code
) - 1, term_code
, strlen(term_code
));
1733 strncat(p
, term_code
, sizeof(term_code
));
1736 } else if (remotehostname
)
1737 snprintf(prompt
, sizeof(prompt
), ASTERISK_PROMPT2
, remotehostname
);
1739 snprintf(prompt
, sizeof(prompt
), ASTERISK_PROMPT
);
1744 static char **ast_el_strtoarr(char *buf
)
1746 char **match_list
= NULL
, *retstr
;
1747 size_t match_list_len
;
1751 while ( (retstr
= strsep(&buf
, " ")) != NULL
) {
1753 if (!strcmp(retstr
, AST_CLI_COMPLETE_EOF
))
1755 if (matches
+ 1 >= match_list_len
) {
1756 match_list_len
<<= 1;
1757 if (!(match_list
= ast_realloc(match_list
, match_list_len
* sizeof(char *)))) {
1758 /* TODO: Handle memory allocation failure */
1762 match_list
[matches
++] = strdup(retstr
);
1766 return (char **) NULL
;
1768 if (matches
>= match_list_len
) {
1769 if (!(match_list
= ast_realloc(match_list
, (match_list_len
+ 1) * sizeof(char *)))) {
1770 /* TODO: Handle memory allocation failure */
1774 match_list
[matches
] = (char *) NULL
;
1779 static int ast_el_sort_compare(const void *i1
, const void *i2
)
1783 s1
= ((char **)i1
)[0];
1784 s2
= ((char **)i2
)[0];
1786 return strcasecmp(s1
, s2
);
1789 static int ast_cli_display_match_list(char **matches
, int len
, int max
)
1791 int i
, idx
, limit
, count
;
1792 int screenwidth
= 0;
1793 int numoutput
= 0, numoutputline
= 0;
1795 screenwidth
= ast_get_termcols(STDOUT_FILENO
);
1797 /* find out how many entries can be put on one line, with two spaces between strings */
1798 limit
= screenwidth
/ (max
+ 2);
1802 /* how many lines of output */
1803 count
= len
/ limit
;
1804 if (count
* limit
< len
)
1809 qsort(&matches
[0], (size_t)(len
), sizeof(char *), ast_el_sort_compare
);
1811 for (; count
> 0; count
--) {
1813 for (i
=0; i
< limit
&& matches
[idx
]; i
++, idx
++) {
1815 /* Don't print dupes */
1816 if ( (matches
[idx
+1] != NULL
&& strcmp(matches
[idx
], matches
[idx
+1]) == 0 ) ) {
1819 matches
[idx
] = NULL
;
1825 fprintf(stdout
, "%-*s ", max
, matches
[idx
]);
1827 matches
[idx
] = NULL
;
1829 if (numoutputline
> 0)
1830 fprintf(stdout
, "\n");
1837 static char *cli_complete(EditLine
*el
, int ch
)
1843 int retval
= CC_ERROR
;
1847 LineInfo
*lf
= (LineInfo
*)el_line(el
);
1849 *(char *)lf
->cursor
= '\0';
1850 ptr
= (char *)lf
->cursor
;
1852 while (ptr
> lf
->buffer
) {
1853 if (isspace(*ptr
)) {
1861 len
= lf
->cursor
- ptr
;
1863 if (ast_opt_remote
) {
1864 snprintf(buf
, sizeof(buf
),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf
->buffer
, ptr
);
1865 fdprint(ast_consock
, buf
);
1866 res
= read(ast_consock
, buf
, sizeof(buf
));
1868 nummatches
= atoi(buf
);
1870 if (nummatches
> 0) {
1872 int mlen
= 0, maxmbuf
= 2048;
1873 /* Start with a 2048 byte buffer */
1874 if (!(mbuf
= ast_malloc(maxmbuf
)))
1875 return (char *)(CC_ERROR
);
1876 snprintf(buf
, sizeof(buf
),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf
->buffer
, ptr
);
1877 fdprint(ast_consock
, buf
);
1880 while (!strstr(mbuf
, AST_CLI_COMPLETE_EOF
) && res
!= -1) {
1881 if (mlen
+ 1024 > maxmbuf
) {
1882 /* Every step increment buffer 1024 bytes */
1884 if (!(mbuf
= ast_realloc(mbuf
, maxmbuf
)))
1885 return (char *)(CC_ERROR
);
1887 /* Only read 1024 bytes at a time */
1888 res
= read(ast_consock
, mbuf
+ mlen
, 1024);
1894 matches
= ast_el_strtoarr(mbuf
);
1897 matches
= (char **) NULL
;
1899 char **p
, *oldbuf
=NULL
;
1901 matches
= ast_cli_completion_matches((char *)lf
->buffer
,ptr
);
1902 for (p
= matches
; p
&& *p
; p
++) {
1903 if (!oldbuf
|| strcmp(*p
,oldbuf
))
1911 int matches_num
, maxlen
, match_len
;
1913 if (matches
[0][0] != '\0') {
1914 el_deletestr(el
, (int) len
);
1915 el_insertstr(el
, matches
[0]);
1916 retval
= CC_REFRESH
;
1919 if (nummatches
== 1) {
1920 /* Found an exact match */
1921 el_insertstr(el
, " ");
1922 retval
= CC_REFRESH
;
1924 /* Must be more than one match */
1925 for (i
=1, maxlen
=0; matches
[i
]; i
++) {
1926 match_len
= strlen(matches
[i
]);
1927 if (match_len
> maxlen
)
1930 matches_num
= i
- 1;
1931 if (matches_num
>1) {
1932 fprintf(stdout
, "\n");
1933 ast_cli_display_match_list(matches
, nummatches
, maxlen
);
1934 retval
= CC_REDISPLAY
;
1936 el_insertstr(el
," ");
1937 retval
= CC_REFRESH
;
1943 return (char *)(long)retval
;
1946 static int ast_el_initialize(void)
1949 char *editor
= getenv("AST_EDITOR");
1953 if (el_hist
!= NULL
)
1954 history_end(el_hist
);
1956 el
= el_init("asterisk", stdin
, stdout
, stderr
);
1957 el_set(el
, EL_PROMPT
, cli_prompt
);
1959 el_set(el
, EL_EDITMODE
, 1);
1960 el_set(el
, EL_EDITOR
, editor
? editor
: "emacs");
1961 el_hist
= history_init();
1962 if (!el
|| !el_hist
)
1965 /* setup history with 100 entries */
1966 history(el_hist
, &ev
, H_SETSIZE
, 100);
1968 el_set(el
, EL_HIST
, history
, el_hist
);
1970 el_set(el
, EL_ADDFN
, "ed-complete", "Complete argument", cli_complete
);
1971 /* Bind <tab> to command completion */
1972 el_set(el
, EL_BIND
, "^I", "ed-complete", NULL
);
1973 /* Bind ? to command completion */
1974 el_set(el
, EL_BIND
, "?", "ed-complete", NULL
);
1975 /* Bind ^D to redisplay */
1976 el_set(el
, EL_BIND
, "^D", "ed-redisplay", NULL
);
1981 static int ast_el_add_history(char *buf
)
1985 if (el_hist
== NULL
|| el
== NULL
)
1986 ast_el_initialize();
1987 if (strlen(buf
) > 256)
1989 return (history(el_hist
, &ev
, H_ENTER
, buf
));
1992 static int ast_el_write_history(char *filename
)
1996 if (el_hist
== NULL
|| el
== NULL
)
1997 ast_el_initialize();
1999 return (history(el_hist
, &ev
, H_SAVE
, filename
));
2002 static int ast_el_read_history(char *filename
)
2008 if (el_hist
== NULL
|| el
== NULL
)
2009 ast_el_initialize();
2011 if ((f
= fopen(filename
, "r")) == NULL
)
2015 fgets(buf
, sizeof(buf
), f
);
2016 if (!strcmp(buf
, "_HiStOrY_V2_\n"))
2018 if (ast_all_zeros(buf
))
2020 if ((ret
= ast_el_add_history(buf
)) == -1)
2028 static void ast_remotecontrol(char * data
)
2032 char filename
[80] = "";
2038 char *stringp
= NULL
;
2043 read(ast_consock
, buf
, sizeof(buf
));
2045 write(ast_consock
, data
, strlen(data
) + 1);
2047 hostname
= strsep(&stringp
, "/");
2048 cpid
= strsep(&stringp
, "/");
2049 version
= strsep(&stringp
, "\n");
2051 version
= "<Version Unknown>";
2053 strsep(&stringp
, ".");
2058 snprintf(tmp
, sizeof(tmp
), "set verbose atleast %d", option_verbose
);
2059 fdprint(ast_consock
, tmp
);
2060 snprintf(tmp
, sizeof(tmp
), "set debug atleast %d", option_debug
);
2061 fdprint(ast_consock
, tmp
);
2063 snprintf(tmp
, sizeof(tmp
), "log and verbose output currently muted ('logger unmute' to unmute)");
2064 fdprint(ast_consock
, tmp
);
2066 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version
, hostname
, pid
);
2067 remotehostname
= hostname
;
2069 snprintf(filename
, sizeof(filename
), "%s/.asterisk_history", getenv("HOME"));
2070 if (el_hist
== NULL
|| el
== NULL
)
2071 ast_el_initialize();
2073 el_set(el
, EL_GETCFN
, ast_el_read_char
);
2075 if (!ast_strlen_zero(filename
))
2076 ast_el_read_history(filename
);
2078 if (ast_opt_exec
&& data
) { /* hack to print output then exit if asterisk -rx is used */
2081 fds
.fd
= ast_consock
;
2082 fds
.events
= POLLIN
;
2084 while (poll(&fds
, 1, 100) > 0)
2085 ast_el_read_char(el
, &tempchar
);
2089 ebuf
= (char *)el_gets(el
, &num
);
2091 if (!ast_strlen_zero(ebuf
)) {
2092 if (ebuf
[strlen(ebuf
)-1] == '\n')
2093 ebuf
[strlen(ebuf
)-1] = '\0';
2094 if (!remoteconsolehandler(ebuf
)) {
2095 res
= write(ast_consock
, ebuf
, strlen(ebuf
) + 1);
2097 ast_log(LOG_WARNING
, "Unable to write: %s\n", strerror(errno
));
2103 printf("\nDisconnected from Asterisk server\n");
2106 static int show_version(void)
2108 printf("Asterisk " ASTERISK_VERSION
"\n");
2112 static int show_cli_help(void) {
2113 printf("Asterisk " ASTERISK_VERSION
", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2114 printf("Usage: asterisk [OPTIONS]\n");
2115 printf("Valid Options:\n");
2116 printf(" -V Display version number and exit\n");
2117 printf(" -C <configfile> Use an alternate configuration file\n");
2118 printf(" -G <group> Run as a group other than the caller\n");
2119 printf(" -U <user> Run as a user other than the caller\n");
2120 printf(" -c Provide console CLI\n");
2121 printf(" -d Enable extra debugging\n");
2122 printf(" -f Do not fork\n");
2123 printf(" -g Dump core in case of a crash\n");
2124 printf(" -h This help screen\n");
2125 printf(" -i Initialize crypto keys at startup\n");
2126 printf(" -I Enable internal timing if Zaptel timer is available\n");
2127 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2128 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2129 printf(" -m Mute the console from debugging and verbose output\n");
2130 printf(" -n Disable console colorization\n");
2131 printf(" -p Run as pseudo-realtime thread\n");
2132 printf(" -q Quiet mode (suppress output)\n");
2133 printf(" -r Connect to Asterisk on this machine\n");
2134 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2135 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2136 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2137 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2138 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2143 static void ast_readconfig(void)
2145 struct ast_config
*cfg
;
2146 struct ast_variable
*v
;
2147 char *config
= AST_CONFIG_FILE
;
2149 if (ast_opt_override_config
) {
2150 cfg
= ast_config_load(ast_config_AST_CONFIG_FILE
);
2152 ast_log(LOG_WARNING
, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE
);
2154 cfg
= ast_config_load(config
);
2157 /* init with buildtime config */
2158 ast_copy_string(ast_config_AST_CONFIG_DIR
, AST_CONFIG_DIR
, sizeof(ast_config_AST_CONFIG_DIR
));
2159 ast_copy_string(ast_config_AST_SPOOL_DIR
, AST_SPOOL_DIR
, sizeof(ast_config_AST_SPOOL_DIR
));
2160 ast_copy_string(ast_config_AST_MODULE_DIR
, AST_MODULE_DIR
, sizeof(ast_config_AST_MODULE_DIR
));
2161 snprintf(ast_config_AST_MONITOR_DIR
, sizeof(ast_config_AST_MONITOR_DIR
) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR
);
2162 ast_copy_string(ast_config_AST_VAR_DIR
, AST_VAR_DIR
, sizeof(ast_config_AST_VAR_DIR
));
2163 ast_copy_string(ast_config_AST_DATA_DIR
, AST_DATA_DIR
, sizeof(ast_config_AST_DATA_DIR
));
2164 ast_copy_string(ast_config_AST_LOG_DIR
, AST_LOG_DIR
, sizeof(ast_config_AST_LOG_DIR
));
2165 ast_copy_string(ast_config_AST_AGI_DIR
, AST_AGI_DIR
, sizeof(ast_config_AST_AGI_DIR
));
2166 ast_copy_string(ast_config_AST_DB
, AST_DB
, sizeof(ast_config_AST_DB
));
2167 ast_copy_string(ast_config_AST_KEY_DIR
, AST_KEY_DIR
, sizeof(ast_config_AST_KEY_DIR
));
2168 ast_copy_string(ast_config_AST_PID
, AST_PID
, sizeof(ast_config_AST_PID
));
2169 ast_copy_string(ast_config_AST_SOCKET
, AST_SOCKET
, sizeof(ast_config_AST_SOCKET
));
2170 ast_copy_string(ast_config_AST_RUN_DIR
, AST_RUN_DIR
, sizeof(ast_config_AST_RUN_DIR
));
2172 /* no asterisk.conf? no problem, use buildtime config! */
2177 for (v
= ast_variable_browse(cfg
, "files"); v
; v
= v
->next
) {
2178 if (!strcasecmp(v
->name
, "astctlpermissions")) {
2179 ast_copy_string(ast_config_AST_CTL_PERMISSIONS
, v
->value
, sizeof(ast_config_AST_CTL_PERMISSIONS
));
2180 } else if (!strcasecmp(v
->name
, "astctlowner")) {
2181 ast_copy_string(ast_config_AST_CTL_OWNER
, v
->value
, sizeof(ast_config_AST_CTL_OWNER
));
2182 } else if (!strcasecmp(v
->name
, "astctlgroup")) {
2183 ast_copy_string(ast_config_AST_CTL_GROUP
, v
->value
, sizeof(ast_config_AST_CTL_GROUP
));
2184 } else if (!strcasecmp(v
->name
, "astctl")) {
2185 ast_copy_string(ast_config_AST_CTL
, v
->value
, sizeof(ast_config_AST_CTL
));
2189 for (v
= ast_variable_browse(cfg
, "directories"); v
; v
= v
->next
) {
2190 if (!strcasecmp(v
->name
, "astetcdir")) {
2191 ast_copy_string(ast_config_AST_CONFIG_DIR
, v
->value
, sizeof(ast_config_AST_CONFIG_DIR
));
2192 } else if (!strcasecmp(v
->name
, "astspooldir")) {
2193 ast_copy_string(ast_config_AST_SPOOL_DIR
, v
->value
, sizeof(ast_config_AST_SPOOL_DIR
));
2194 snprintf(ast_config_AST_MONITOR_DIR
, sizeof(ast_config_AST_MONITOR_DIR
) - 1, "%s/monitor", v
->value
);
2195 } else if (!strcasecmp(v
->name
, "astvarlibdir")) {
2196 ast_copy_string(ast_config_AST_VAR_DIR
, v
->value
, sizeof(ast_config_AST_VAR_DIR
));
2197 snprintf(ast_config_AST_DB
, sizeof(ast_config_AST_DB
), "%s/astdb", v
->value
);
2198 } else if (!strcasecmp(v
->name
, "astdatadir")) {
2199 ast_copy_string(ast_config_AST_DATA_DIR
, v
->value
, sizeof(ast_config_AST_DATA_DIR
));
2200 snprintf(ast_config_AST_KEY_DIR
, sizeof(ast_config_AST_KEY_DIR
), "%s/keys", v
->value
);
2201 } else if (!strcasecmp(v
->name
, "astlogdir")) {
2202 ast_copy_string(ast_config_AST_LOG_DIR
, v
->value
, sizeof(ast_config_AST_LOG_DIR
));
2203 } else if (!strcasecmp(v
->name
, "astagidir")) {
2204 ast_copy_string(ast_config_AST_AGI_DIR
, v
->value
, sizeof(ast_config_AST_AGI_DIR
));
2205 } else if (!strcasecmp(v
->name
, "astrundir")) {
2206 snprintf(ast_config_AST_PID
, sizeof(ast_config_AST_PID
), "%s/%s", v
->value
, "asterisk.pid");
2207 snprintf(ast_config_AST_SOCKET
, sizeof(ast_config_AST_SOCKET
), "%s/%s", v
->value
, ast_config_AST_CTL
);
2208 ast_copy_string(ast_config_AST_RUN_DIR
, v
->value
, sizeof(ast_config_AST_RUN_DIR
));
2209 } else if (!strcasecmp(v
->name
, "astmoddir")) {
2210 ast_copy_string(ast_config_AST_MODULE_DIR
, v
->value
, sizeof(ast_config_AST_MODULE_DIR
));
2214 for (v
= ast_variable_browse(cfg
, "options"); v
; v
= v
->next
) {
2215 /* verbose level (-v at startup) */
2216 if (!strcasecmp(v
->name
, "verbose")) {
2217 option_verbose
= atoi(v
->value
);
2218 /* whether or not to force timestamping. (-T at startup) */
2219 } else if (!strcasecmp(v
->name
, "timestamp")) {
2220 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_TIMESTAMP
);
2221 /* whether or not to support #exec in config files */
2222 } else if (!strcasecmp(v
->name
, "execincludes")) {
2223 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_EXEC_INCLUDES
);
2224 /* debug level (-d at startup) */
2225 } else if (!strcasecmp(v
->name
, "debug")) {
2227 if (sscanf(v
->value
, "%d", &option_debug
) != 1) {
2228 option_debug
= ast_true(v
->value
);
2230 /* Disable forking (-f at startup) */
2231 } else if (!strcasecmp(v
->name
, "nofork")) {
2232 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_NO_FORK
);
2233 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2234 } else if (!strcasecmp(v
->name
, "alwaysfork")) {
2235 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_ALWAYS_FORK
);
2236 /* Run quietly (-q at startup ) */
2237 } else if (!strcasecmp(v
->name
, "quiet")) {
2238 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_QUIET
);
2239 /* Run as console (-c at startup, implies nofork) */
2240 } else if (!strcasecmp(v
->name
, "console")) {
2241 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_CONSOLE
);
2242 /* Run with high priority if the O/S permits (-p at startup) */
2243 } else if (!strcasecmp(v
->name
, "highpriority")) {
2244 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_HIGH_PRIORITY
);
2245 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2246 } else if (!strcasecmp(v
->name
, "initcrypto")) {
2247 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_INIT_KEYS
);
2248 /* Disable ANSI colors for console (-c at startup) */
2249 } else if (!strcasecmp(v
->name
, "nocolor")) {
2250 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_NO_COLOR
);
2251 /* Disable some usage warnings for picky people :p */
2252 } else if (!strcasecmp(v
->name
, "dontwarn")) {
2253 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_DONT_WARN
);
2254 /* Dump core in case of crash (-g) */
2255 } else if (!strcasecmp(v
->name
, "dumpcore")) {
2256 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_DUMP_CORE
);
2257 /* Cache recorded sound files to another directory during recording */
2258 } else if (!strcasecmp(v
->name
, "cache_record_files")) {
2259 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_CACHE_RECORD_FILES
);
2260 /* Specify cache directory */
2261 } else if (!strcasecmp(v
->name
, "record_cache_dir")) {
2262 ast_copy_string(record_cache_dir
, v
->value
, AST_CACHE_DIR_LEN
);
2263 /* Build transcode paths via SLINEAR, instead of directly */
2264 } else if (!strcasecmp(v
->name
, "transcode_via_sln")) {
2265 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_TRANSCODE_VIA_SLIN
);
2266 /* Transmit SLINEAR silence while a channel is being recorded */
2267 } else if (!strcasecmp(v
->name
, "transmit_silence_during_record")) {
2268 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_TRANSMIT_SILENCE
);
2269 /* Enable internal timing */
2270 } else if (!strcasecmp(v
->name
, "internal_timing")) {
2271 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_INTERNAL_TIMING
);
2272 } else if (!strcasecmp(v
->name
, "maxcalls")) {
2273 if ((sscanf(v
->value
, "%d", &option_maxcalls
) != 1) || (option_maxcalls
< 0)) {
2274 option_maxcalls
= 0;
2276 } else if (!strcasecmp(v
->name
, "maxload")) {
2279 if (getloadavg(test
, 1) == -1) {
2280 ast_log(LOG_ERROR
, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2281 option_maxload
= 0.0;
2282 } else if ((sscanf(v
->value
, "%lf", &option_maxload
) != 1) || (option_maxload
< 0.0)) {
2283 option_maxload
= 0.0;
2285 /* What user to run as */
2286 } else if (!strcasecmp(v
->name
, "runuser")) {
2287 ast_copy_string(ast_config_AST_RUN_USER
, v
->value
, sizeof(ast_config_AST_RUN_USER
));
2288 /* What group to run as */
2289 } else if (!strcasecmp(v
->name
, "rungroup")) {
2290 ast_copy_string(ast_config_AST_RUN_GROUP
, v
->value
, sizeof(ast_config_AST_RUN_GROUP
));
2291 } else if (!strcasecmp(v
->name
, "systemname")) {
2292 ast_copy_string(ast_config_AST_SYSTEM_NAME
, v
->value
, sizeof(ast_config_AST_SYSTEM_NAME
));
2293 } else if (!strcasecmp(v
->name
, "languageprefix")) {
2294 ast_language_is_prefix
= ast_true(v
->value
);
2297 ast_config_destroy(cfg
);
2300 int main(int argc
, char *argv
[])
2303 char filename
[80] = "";
2304 char hostname
[MAXHOSTNAMELEN
] = "";
2311 int is_child_of_nonroot
= 0;
2313 char *runuser
= NULL
, *rungroup
= NULL
;
2315 /* Remember original args for restart */
2316 if (argc
> sizeof(_argv
) / sizeof(_argv
[0]) - 1) {
2317 fprintf(stderr
, "Truncating argument size to %d\n", (int)(sizeof(_argv
) / sizeof(_argv
[0])) - 1);
2318 argc
= sizeof(_argv
) / sizeof(_argv
[0]) - 1;
2320 for (x
=0; x
<argc
; x
++)
2324 /* if the progname is rasterisk consider it a remote console */
2325 if (argv
[0] && (strstr(argv
[0], "rasterisk")) != NULL
) {
2326 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
| AST_OPT_FLAG_REMOTE
);
2328 if (gethostname(hostname
, sizeof(hostname
)-1))
2329 ast_copy_string(hostname
, "<Unknown>", sizeof(hostname
));
2330 ast_mainpid
= getpid();
2334 ast_builtins_init();
2337 /* When Asterisk restarts after it has dropped the root privileges,
2338 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2340 if (getenv("ASTERISK_ALREADY_NONROOT"))
2341 is_child_of_nonroot
=1;
2343 snprintf(filename
, sizeof(filename
), "%s/.asterisk_history", getenv("HOME"));
2344 /* Check for options */
2345 while ((c
= getopt(argc
, argv
, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2348 ast_set_flag(&ast_options
, AST_OPT_FLAG_ALWAYS_FORK
);
2352 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
);
2355 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
| AST_OPT_FLAG_CONSOLE
);
2358 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
);
2361 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_COLOR
);
2364 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
| AST_OPT_FLAG_REMOTE
);
2367 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
| AST_OPT_FLAG_REMOTE
| AST_OPT_FLAG_RECONNECT
);
2370 ast_set_flag(&ast_options
, AST_OPT_FLAG_HIGH_PRIORITY
);
2374 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
);
2377 ast_set_flag(&ast_options
, AST_OPT_FLAG_MUTE
);
2380 if ((sscanf(optarg
, "%d", &option_maxcalls
) != 1) || (option_maxcalls
< 0))
2381 option_maxcalls
= 0;
2384 if ((sscanf(optarg
, "%lf", &option_maxload
) != 1) || (option_maxload
< 0.0))
2385 option_maxload
= 0.0;
2388 ast_set_flag(&ast_options
, AST_OPT_FLAG_QUIET
);
2391 ast_set_flag(&ast_options
, AST_OPT_FLAG_CACHE_RECORD_FILES
);
2394 ast_set_flag(&ast_options
, AST_OPT_FLAG_TIMESTAMP
);
2397 ast_set_flag(&ast_options
, AST_OPT_FLAG_EXEC
);
2401 ast_copy_string(ast_config_AST_CONFIG_FILE
, optarg
, sizeof(ast_config_AST_CONFIG_FILE
));
2402 ast_set_flag(&ast_options
, AST_OPT_FLAG_OVERRIDE_CONFIG
);
2405 ast_set_flag(&ast_options
, AST_OPT_FLAG_INTERNAL_TIMING
);
2408 ast_set_flag(&ast_options
, AST_OPT_FLAG_INIT_KEYS
);
2411 ast_set_flag(&ast_options
, AST_OPT_FLAG_DUMP_CORE
);
2430 if (ast_opt_always_fork
&& (ast_opt_remote
|| ast_opt_console
)) {
2431 ast_log(LOG_WARNING
, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2432 ast_clear_flag(&ast_options
, AST_OPT_FLAG_ALWAYS_FORK
);
2435 /* For remote connections, change the name of the remote connection.
2436 * We do this for the benefit of init scripts (which need to know if/when
2437 * the main asterisk process has died yet). */
2438 if (ast_opt_remote
) {
2439 strcpy(argv
[0], "rasterisk");
2440 for (x
= 1; x
< argc
; x
++) {
2441 argv
[x
] = argv
[0] + 10;
2445 if (ast_opt_console
&& !option_verbose
)
2446 ast_verbose("[ Reading Master Configuration ]");
2449 if (ast_opt_dump_core
) {
2451 memset(&l
, 0, sizeof(l
));
2452 l
.rlim_cur
= RLIM_INFINITY
;
2453 l
.rlim_max
= RLIM_INFINITY
;
2454 if (setrlimit(RLIMIT_CORE
, &l
)) {
2455 ast_log(LOG_WARNING
, "Unable to disable core size resource limit: %s\n", strerror(errno
));
2459 if ((!rungroup
) && !ast_strlen_zero(ast_config_AST_RUN_GROUP
))
2460 rungroup
= ast_config_AST_RUN_GROUP
;
2461 if ((!runuser
) && !ast_strlen_zero(ast_config_AST_RUN_USER
))
2462 runuser
= ast_config_AST_RUN_USER
;
2466 if (!is_child_of_nonroot
)
2467 ast_set_priority(ast_opt_high_priority
);
2469 if (!is_child_of_nonroot
&& rungroup
) {
2471 gr
= getgrnam(rungroup
);
2473 ast_log(LOG_WARNING
, "No such group '%s'!\n", rungroup
);
2476 if (setgid(gr
->gr_gid
)) {
2477 ast_log(LOG_WARNING
, "Unable to setgid to %d (%s)\n", (int)gr
->gr_gid
, rungroup
);
2480 if (setgroups(0, NULL
)) {
2481 ast_log(LOG_WARNING
, "Unable to drop unneeded groups\n");
2485 ast_verbose("Running as group '%s'\n", rungroup
);
2488 if (!is_child_of_nonroot
&& runuser
) {
2490 pw
= getpwnam(runuser
);
2492 ast_log(LOG_WARNING
, "No such user '%s'!\n", runuser
);
2496 if (setgid(pw
->pw_gid
)) {
2497 ast_log(LOG_WARNING
, "Unable to setgid to %d!\n", (int)pw
->pw_gid
);
2500 if (initgroups(pw
->pw_name
, pw
->pw_gid
)) {
2501 ast_log(LOG_WARNING
, "Unable to init groups for '%s'\n", runuser
);
2505 if (setuid(pw
->pw_uid
)) {
2506 ast_log(LOG_WARNING
, "Unable to setuid to %d (%s)\n", (int)pw
->pw_uid
, runuser
);
2509 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2511 ast_verbose("Running as user '%s'\n", runuser
);
2514 #endif /* __CYGWIN__ */
2517 if (geteuid() && ast_opt_dump_core
) {
2518 if (prctl(PR_SET_DUMPABLE
, 1, 0, 0, 0) < 0) {
2519 ast_log(LOG_WARNING
, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno
));
2528 if (ast_opt_console
&& !option_verbose
)
2529 ast_verbose("[ Initializing Custom Configuration Options ]");
2530 /* custom config setup */
2531 register_config_cli();
2534 if (ast_opt_console
) {
2535 if (el_hist
== NULL
|| el
== NULL
)
2536 ast_el_initialize();
2538 if (!ast_strlen_zero(filename
))
2539 ast_el_read_history(filename
);
2542 if (ast_tryconnect()) {
2543 /* One is already running */
2544 if (ast_opt_remote
) {
2546 ast_remotecontrol(xarg
);
2547 quit_handler(0, 0, 0, 0);
2550 printf(term_quit());
2551 ast_register_verbose(console_verboser
);
2553 ast_remotecontrol(NULL
);
2554 quit_handler(0, 0, 0, 0);
2557 ast_log(LOG_ERROR
, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET
);
2558 printf(term_quit());
2561 } else if (ast_opt_remote
|| ast_opt_exec
) {
2562 ast_log(LOG_ERROR
, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET
);
2563 printf(term_quit());
2566 /* Blindly write pid file since we couldn't connect */
2567 unlink(ast_config_AST_PID
);
2568 f
= fopen(ast_config_AST_PID
, "w");
2570 fprintf(f
, "%ld\n", (long)getpid());
2573 ast_log(LOG_WARNING
, "Unable to open pid file '%s': %s\n", ast_config_AST_PID
, strerror(errno
));
2575 if (ast_opt_always_fork
|| !ast_opt_no_fork
) {
2577 ast_mainpid
= getpid();
2578 /* Blindly re-write pid file since we are forking */
2579 unlink(ast_config_AST_PID
);
2580 f
= fopen(ast_config_AST_PID
, "w");
2582 fprintf(f
, "%ld\n", (long)ast_mainpid
);
2585 ast_log(LOG_WARNING
, "Unable to open pid file '%s': %s\n", ast_config_AST_PID
, strerror(errno
));
2588 /* Test recursive mutex locking. */
2589 if (test_for_thread_safety())
2590 ast_verbose("Warning! Asterisk is not thread safe.\n");
2594 sigaddset(&sigs
, SIGHUP
);
2595 sigaddset(&sigs
, SIGTERM
);
2596 sigaddset(&sigs
, SIGINT
);
2597 sigaddset(&sigs
, SIGPIPE
);
2598 sigaddset(&sigs
, SIGWINCH
);
2599 pthread_sigmask(SIG_BLOCK
, &sigs
, NULL
);
2600 if (ast_opt_console
|| option_verbose
|| ast_opt_remote
)
2601 ast_register_verbose(console_verboser
);
2602 /* Print a welcome message if desired */
2603 if (option_verbose
|| ast_opt_console
) {
2606 if (ast_opt_console
&& !option_verbose
)
2607 ast_verbose("[ Booting...");
2609 signal(SIGURG
, urg_handler
);
2610 signal(SIGINT
, __quit_handler
);
2611 signal(SIGTERM
, __quit_handler
);
2612 signal(SIGHUP
, hup_handler
);
2613 signal(SIGCHLD
, child_handler
);
2614 signal(SIGPIPE
, SIG_IGN
);
2616 /* ensure that the random number generators are seeded with a different value every time
2619 srand((unsigned int) getpid() + (unsigned int) time(NULL
));
2620 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL
), randompool
, sizeof(randompool
));
2622 if (init_logger()) {
2623 printf(term_quit());
2626 if (dnsmgr_init()) {
2627 printf(term_quit());
2630 /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2631 if (load_modules(1)) {
2632 printf(term_quit());
2636 ast_channels_init();
2637 if (init_manager()) {
2638 printf(term_quit());
2641 if (ast_cdr_engine_init()) {
2642 printf(term_quit());
2645 if (ast_device_state_engine_init()) {
2646 printf(term_quit());
2651 if (ast_image_init()) {
2652 printf(term_quit());
2655 if (ast_file_init()) {
2656 printf(term_quit());
2660 printf(term_quit());
2663 if (load_modules(0)) {
2664 printf(term_quit());
2667 if (init_framer()) {
2668 printf(term_quit());
2672 printf(term_quit());
2675 if (ast_enum_init()) {
2676 printf(term_quit());
2680 dnsmgr_start_refresh();
2683 /* This should no longer be necessary */
2684 /* sync cust config and reload some internals in case a custom config handler binded to them */
2685 read_ast_cust_config();
2692 /* We might have the option of showing a console, but for now just
2694 if (ast_opt_console
&& !option_verbose
)
2695 ast_verbose(" ]\n");
2696 if (option_verbose
|| ast_opt_console
)
2697 ast_verbose(term_color(tmp
, "Asterisk Ready.\n", COLOR_BRWHITE
, COLOR_BLACK
, sizeof(tmp
)));
2698 if (ast_opt_no_fork
)
2699 consolethread
= pthread_self();
2700 ast_set_flag(&ast_options
, AST_OPT_FLAG_FULLY_BOOTED
);
2701 pthread_sigmask(SIG_UNBLOCK
, &sigs
, NULL
);
2702 #ifdef __AST_DEBUG_MALLOC
2705 time(&ast_startuptime
);
2706 ast_cli_register_multiple(core_cli
, sizeof(core_cli
) / sizeof(core_cli
[0]));
2707 if (ast_opt_console
) {
2708 /* Console stuff now... */
2709 /* Register our quit function */
2711 set_icon("Asterisk");
2712 snprintf(title
, sizeof(title
), "Asterisk Console on '%s' (pid %ld)", hostname
, (long)ast_mainpid
);
2716 buf
= (char *)el_gets(el
, &num
);
2718 if (buf
[strlen(buf
)-1] == '\n')
2719 buf
[strlen(buf
)-1] = '\0';
2721 consolehandler((char *)buf
);
2723 if (write(STDOUT_FILENO
, "\nUse EXIT or QUIT to exit the asterisk console\n",
2724 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2725 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2727 fd
= open("/dev/null", O_RDWR
);
2729 dup2(fd
, STDOUT_FILENO
);
2730 dup2(fd
, STDIN_FILENO
);
2732 ast_log(LOG_WARNING
, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2740 for(;;) { /* apparently needed for the MACos */
2741 struct pollfd p
= { -1 /* no descriptor */, 0, 0 };