2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
20 /* Doxygenified Copyright Header */
22 * \mainpage Asterisk -- An Open Source Telephony Toolkit
24 * \par Developer Documentation for Asterisk
25 * This is the main developer documentation for Asterisk. It is
26 * generated by running "make progdocs".
27 * \par Additional documentation
29 * \arg \ref ConfigFiles
31 * \section copyright Copyright and author
33 * Copyright (C) 1999 - 2006, Digium, Inc.
34 * Asterisk is a trade mark registered by Digium, Inc.
36 * \author Mark Spencer <markster@digium.com>
37 * Also see \ref AstCREDITS
39 * \section license License
40 * See http://www.asterisk.org for more information about
41 * the Asterisk project. Please do not directly contact
42 * any of the maintainers of this project for assistance;
43 * the project provides a web site, mailing lists and IRC
44 * channels for your use.
46 * This program is free software, distributed under the terms of
47 * the GNU General Public License Version 2. See the LICENSE file
48 * at the top of the source tree.
50 * \verbinclude LICENSE
55 \brief Top level source file for Asterisk - the Open Source PBX. Implementation
56 of PBX core functions and CLI interface.
67 #include <sys/socket.h>
73 #include <sys/resource.h>
78 #include <sys/prctl.h>
83 #include <sys/prctl.h>
86 #if defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
89 extern int daemon(int, int); /* defined in libresolv of all places */
95 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
97 #include "asterisk/logger.h"
98 #include "asterisk/options.h"
99 #include "asterisk/cli.h"
100 #include "asterisk/channel.h"
101 #include "asterisk/ulaw.h"
102 #include "asterisk/alaw.h"
103 #include "asterisk/callerid.h"
104 #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"
125 #include "asterisk/compat.h"
127 #include "asterisk/doxyref.h" /* Doxygen documentation */
129 #include "defaults.h"
132 #define AF_LOCAL AF_UNIX
133 #define PF_LOCAL PF_UNIX
136 #define AST_MAX_CONNECTS 128
139 /*! \brief Welcome message when starting a CLI interface */
140 #define WELCOME_MESSAGE \
141 ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2006 Digium, Inc. and others.\n"); \
142 ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
143 ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
144 ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
145 ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
146 ast_verbose("certain conditions. Type 'show license' for details.\n"); \
147 ast_verbose("=========================================================================\n")
149 /*! \defgroup main_options
150 \brief Main configuration options from \ref Config_ast "asterisk.conf" or
151 the operating system command line when starting Asterisk
152 Some of them can be changed in the CLI
156 extern int ast_language_is_prefix
; /* XXX move to some header */
158 struct ast_flags ast_options
= { AST_DEFAULT_OPTIONS
};
160 int option_verbose
= 0; /*!< Verbosity level */
161 int option_debug
= 0; /*!< Debug level */
163 double option_maxload
= 0.0; /*!< Max load avg on system */
164 int option_maxcalls
= 0; /*!< Max number of active calls */
168 char record_cache_dir
[AST_CACHE_DIR_LEN
] = AST_TMP_DIR
;
169 char debug_filename
[AST_FILENAME_MAX
] = "";
171 static int ast_socket
= -1; /*!< UNIX Socket for allowing remote control */
172 static int ast_consock
= -1; /*!< UNIX Socket for controlling another asterisk */
175 int fd
; /*!< File descriptor */
176 int p
[2]; /*!< Pipe */
177 pthread_t t
; /*!< Thread of handler */
178 int mute
; /*!< Is the console muted for logs */
183 AST_LIST_ENTRY(ast_atexit
) list
;
186 static AST_LIST_HEAD_STATIC(atexits
, ast_atexit
);
188 time_t ast_startuptime
;
189 time_t ast_lastreloadtime
;
191 static History
*el_hist
= NULL
;
192 static EditLine
*el
= NULL
;
193 static char *remotehostname
;
195 struct console consoles
[AST_MAX_CONNECTS
];
197 char defaultlanguage
[MAX_LANGUAGE
] = DEFAULT_LANGUAGE
;
199 static int ast_el_add_history(char *);
200 static int ast_el_read_history(char *);
201 static int ast_el_write_history(char *);
203 char ast_config_AST_CONFIG_DIR
[AST_CONFIG_MAX_PATH
];
204 char ast_config_AST_CONFIG_FILE
[AST_CONFIG_MAX_PATH
];
205 char ast_config_AST_MODULE_DIR
[AST_CONFIG_MAX_PATH
];
206 char ast_config_AST_SPOOL_DIR
[AST_CONFIG_MAX_PATH
];
207 char ast_config_AST_MONITOR_DIR
[AST_CONFIG_MAX_PATH
];
208 char ast_config_AST_VAR_DIR
[AST_CONFIG_MAX_PATH
];
209 char ast_config_AST_DATA_DIR
[AST_CONFIG_MAX_PATH
];
210 char ast_config_AST_LOG_DIR
[AST_CONFIG_MAX_PATH
];
211 char ast_config_AST_AGI_DIR
[AST_CONFIG_MAX_PATH
];
212 char ast_config_AST_DB
[AST_CONFIG_MAX_PATH
];
213 char ast_config_AST_KEY_DIR
[AST_CONFIG_MAX_PATH
];
214 char ast_config_AST_PID
[AST_CONFIG_MAX_PATH
];
215 char ast_config_AST_SOCKET
[AST_CONFIG_MAX_PATH
];
216 char ast_config_AST_RUN_DIR
[AST_CONFIG_MAX_PATH
];
217 char ast_config_AST_RUN_USER
[AST_CONFIG_MAX_PATH
];
218 char ast_config_AST_RUN_GROUP
[AST_CONFIG_MAX_PATH
];
219 char ast_config_AST_CTL_PERMISSIONS
[AST_CONFIG_MAX_PATH
];
220 char ast_config_AST_CTL_OWNER
[AST_CONFIG_MAX_PATH
] = "\0";
221 char ast_config_AST_CTL_GROUP
[AST_CONFIG_MAX_PATH
] = "\0";
222 char ast_config_AST_CTL
[AST_CONFIG_MAX_PATH
] = "asterisk.ctl";
223 char ast_config_AST_SYSTEM_NAME
[20] = "";
225 extern const char *ast_build_hostname
;
226 extern const char *ast_build_kernel
;
227 extern const char *ast_build_machine
;
228 extern const char *ast_build_os
;
229 extern const char *ast_build_date
;
230 extern const char *ast_build_user
;
232 static char *_argv
[256];
233 static int shuttingdown
= 0;
234 static int restartnow
= 0;
235 static pthread_t consolethread
= AST_PTHREADT_NULL
;
237 static char randompool
[256];
239 #if !defined(LOW_MEMORY)
240 struct file_version
{
241 AST_LIST_ENTRY(file_version
) list
;
246 static AST_LIST_HEAD_STATIC(file_versions
, file_version
);
248 void ast_register_file_version(const char *file
, const char *version
)
250 struct file_version
*new;
252 size_t version_length
;
254 work
= ast_strdupa(version
);
255 work
= ast_strip(ast_strip_quoted(work
, "$", "$"));
256 version_length
= strlen(work
) + 1;
258 if (!(new = ast_calloc(1, sizeof(*new) + version_length
)))
262 new->version
= (char *) new + sizeof(*new);
263 memcpy(new->version
, work
, version_length
);
264 AST_LIST_LOCK(&file_versions
);
265 AST_LIST_INSERT_HEAD(&file_versions
, new, list
);
266 AST_LIST_UNLOCK(&file_versions
);
269 void ast_unregister_file_version(const char *file
)
271 struct file_version
*find
;
273 AST_LIST_LOCK(&file_versions
);
274 AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions
, find
, list
) {
275 if (!strcasecmp(find
->file
, file
)) {
276 AST_LIST_REMOVE_CURRENT(&file_versions
, list
);
280 AST_LIST_TRAVERSE_SAFE_END
;
281 AST_LIST_UNLOCK(&file_versions
);
286 struct thread_list_t
{
287 AST_LIST_ENTRY(thread_list_t
) list
;
292 static AST_LIST_HEAD_STATIC(thread_list
, thread_list_t
);
294 static char show_threads_help
[] =
295 "Usage: show threads\n"
296 " List threads currently active in the system.\n";
298 void ast_register_thread(char *name
)
300 struct thread_list_t
*new = ast_calloc(1, sizeof(*new));
304 new->id
= pthread_self();
305 new->name
= name
; /* this was a copy already */
306 AST_LIST_LOCK(&thread_list
);
307 AST_LIST_INSERT_HEAD(&thread_list
, new, list
);
308 AST_LIST_UNLOCK(&thread_list
);
311 void ast_unregister_thread(void *id
)
313 struct thread_list_t
*x
;
315 AST_LIST_LOCK(&thread_list
);
316 AST_LIST_TRAVERSE_SAFE_BEGIN(&thread_list
, x
, list
) {
317 if ((void *)x
->id
== id
) {
318 AST_LIST_REMOVE_CURRENT(&thread_list
, list
);
322 AST_LIST_TRAVERSE_SAFE_END
;
323 AST_LIST_UNLOCK(&thread_list
);
330 static int handle_show_threads(int fd
, int argc
, char *argv
[])
333 struct thread_list_t
*cur
;
335 AST_LIST_LOCK(&thread_list
);
336 AST_LIST_TRAVERSE(&thread_list
, cur
, list
) {
337 ast_cli(fd
, "%p %s\n", (void *)cur
->id
, cur
->name
);
340 AST_LIST_UNLOCK(&thread_list
);
341 ast_cli(fd
, "%d threads listed.\n", count
);
345 struct profile_entry
{
347 uint64_t scale
; /* if non-zero, values are scaled by this */
353 struct profile_data
{
356 struct profile_entry e
[0];
359 static struct profile_data
*prof_data
;
362 * allocates a counter with a given name and scale.
363 * Returns the identifier of the counter.
365 int ast_add_profile(const char *name
, uint64_t scale
)
367 int l
= sizeof(struct profile_data
);
368 int n
= 10; /* default entries */
370 if (prof_data
== NULL
) {
371 prof_data
= ast_calloc(1, l
+ n
*sizeof(struct profile_entry
));
372 if (prof_data
== NULL
)
374 prof_data
->entries
= 0;
375 prof_data
->max_size
= n
;
377 if (prof_data
->entries
>= prof_data
->max_size
) {
379 n
= prof_data
->max_size
+ 20;
380 p
= ast_realloc(prof_data
, l
+ n
*sizeof(struct profile_entry
));
384 prof_data
->max_size
= n
;
386 n
= prof_data
->entries
++;
387 prof_data
->e
[n
].name
= ast_strdup(name
);
388 prof_data
->e
[n
].value
= 0;
389 prof_data
->e
[n
].events
= 0;
390 prof_data
->e
[n
].mark
= 0;
391 prof_data
->e
[n
].scale
= scale
;
395 int64_t ast_profile(int i
, int64_t delta
)
397 if (!prof_data
|| i
< 0 || i
> prof_data
->entries
) /* invalid index */
399 if (prof_data
->e
[i
].scale
> 1)
400 delta
/= prof_data
->e
[i
].scale
;
401 prof_data
->e
[i
].value
+= delta
;
402 prof_data
->e
[i
].events
++;
403 return prof_data
->e
[i
].value
;
406 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
407 #if defined(__FreeBSD__)
408 #include <machine/cpufunc.h>
410 static __inline u_int64_t
415 __asm
__volatile(".byte 0x0f, 0x31" : "=A" (rv
));
419 #else /* supply a dummy function on other platforms */
420 static __inline u_int64_t
427 int64_t ast_mark(int i
, int startstop
)
429 if (!prof_data
|| i
< 0 || i
> prof_data
->entries
) /* invalid index */
432 prof_data
->e
[i
].mark
= rdtsc();
434 prof_data
->e
[i
].mark
= (rdtsc() - prof_data
->e
[i
].mark
);
435 if (prof_data
->e
[i
].scale
> 1)
436 prof_data
->e
[i
].mark
/= prof_data
->e
[i
].scale
;
437 prof_data
->e
[i
].value
+= prof_data
->e
[i
].mark
;
438 prof_data
->e
[i
].events
++;
440 return prof_data
->e
[i
].mark
;
443 static int handle_show_profile(int fd
, int argc
, char *argv
[])
448 if (prof_data
== NULL
)
452 max
= prof_data
->entries
;
453 if (argc
>= 3) { /* specific entries */
454 if (isdigit(argv
[2][0])) {
456 if (argc
== 4 && strcmp(argv
[3], "-"))
461 if (max
> prof_data
->entries
)
462 max
= prof_data
->entries
;
463 if (!strcmp(argv
[0], "clear")) {
464 for (i
= min
; i
< max
; i
++) {
465 if (!search
|| strstr(prof_data
->e
[i
].name
, search
)) {
466 prof_data
->e
[i
].value
= 0;
467 prof_data
->e
[i
].events
= 0;
472 ast_cli(fd
, "profile values (%d, allocated %d)\n-------------------\n",
473 prof_data
->entries
, prof_data
->max_size
);
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: show version files [like <pattern>]\n"
489 " Shows 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 /*! 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 /*! 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 /*! 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 ast_replace_sigchld();
657 if (ast_opt_high_priority
)
659 /* Close file descriptors and launch system command */
660 for (x
= STDERR_FILENO
+ 1; x
< 4096; x
++)
662 execl("/bin/sh", "/bin/sh", "-c", s
, NULL
);
664 } else if (pid
> 0) {
666 res
= wait4(pid
, &status
, 0, &rusage
);
668 res
= WIFEXITED(status
) ? WEXITSTATUS(status
) : -1;
670 } else if (errno
!= EINTR
)
674 ast_log(LOG_WARNING
, "Fork failed: %s\n", strerror(errno
));
678 ast_unreplace_sigchld();
684 * mute or unmute a console from logging
686 void ast_console_toggle_mute(int fd
) {
688 for (x
= 0;x
< AST_MAX_CONNECTS
; x
++) {
689 if (fd
== consoles
[x
].fd
) {
690 if (consoles
[x
].mute
) {
691 consoles
[x
].mute
= 0;
692 ast_cli(fd
, "Console is not muted anymore.\n");
694 consoles
[x
].mute
= 1;
695 ast_cli(fd
, "Console is muted.\n");
700 ast_cli(fd
, "Couldn't find remote console.\n");
704 * log the string to all attached console clients
706 static void ast_network_puts_mutable(const char *string
)
709 for (x
= 0;x
< AST_MAX_CONNECTS
; x
++) {
710 if (consoles
[x
].mute
)
712 if (consoles
[x
].fd
> -1)
713 fdprint(consoles
[x
].p
[1], string
);
718 * log the string to the console, and all attached
721 void ast_console_puts_mutable(const char *string
)
723 fputs(string
, stdout
);
725 ast_network_puts_mutable(string
);
729 * write the string to all attached console clients
731 static void ast_network_puts(const char *string
)
734 for (x
=0; x
< AST_MAX_CONNECTS
; x
++) {
735 if (consoles
[x
].fd
> -1)
736 fdprint(consoles
[x
].p
[1], string
);
741 * write the string to the console, and all attached
744 void ast_console_puts(const char *string
)
746 fputs(string
, stdout
);
748 ast_network_puts(string
);
751 static void network_verboser(const char *s
, int pos
, int replace
, int complete
)
756 if ((t
= alloca(strlen(s
) + 2))) {
757 sprintf(t
, "\r%s", s
);
759 ast_network_puts_mutable(t
);
761 ast_log(LOG_ERROR
, "Out of memory\n");
762 ast_network_puts_mutable(s
);
766 ast_network_puts_mutable(s
);
770 static pthread_t lthread
;
772 static void *netconsole(void *vconsole
)
774 struct console
*con
= vconsole
;
775 char hostname
[MAXHOSTNAMELEN
] = "";
778 struct pollfd fds
[2];
780 if (gethostname(hostname
, sizeof(hostname
)-1))
781 ast_copy_string(hostname
, "<Unknown>", sizeof(hostname
));
782 snprintf(tmp
, sizeof(tmp
), "%s/%ld/%s\n", hostname
, (long)ast_mainpid
, ASTERISK_VERSION
);
783 fdprint(con
->fd
, tmp
);
786 fds
[0].events
= POLLIN
;
788 fds
[1].fd
= con
->p
[0];
789 fds
[1].events
= POLLIN
;
792 res
= poll(fds
, 2, -1);
795 ast_log(LOG_WARNING
, "poll returned < 0: %s\n", strerror(errno
));
798 if (fds
[0].revents
) {
799 res
= read(con
->fd
, tmp
, sizeof(tmp
));
804 ast_cli_command(con
->fd
, tmp
);
806 if (fds
[1].revents
) {
807 res
= read(con
->p
[0], tmp
, sizeof(tmp
));
809 ast_log(LOG_ERROR
, "read returned %d\n", res
);
812 res
= write(con
->fd
, tmp
, res
);
817 if (option_verbose
> 2)
818 ast_verbose(VERBOSE_PREFIX_3
"Remote UNIX connection disconnected\n");
827 static void *listener(void *unused
)
829 struct sockaddr_un sunaddr
;
834 struct pollfd fds
[1];
836 pthread_attr_init(&attr
);
837 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
841 fds
[0].fd
= ast_socket
;
842 fds
[0].events
= POLLIN
;
843 s
= poll(fds
, 1, -1);
846 ast_log(LOG_WARNING
, "poll returned error: %s\n", strerror(errno
));
849 len
= sizeof(sunaddr
);
850 s
= accept(ast_socket
, (struct sockaddr
*)&sunaddr
, &len
);
853 ast_log(LOG_WARNING
, "Accept returned %d: %s\n", s
, strerror(errno
));
855 for (x
= 0; x
< AST_MAX_CONNECTS
; x
++) {
856 if (consoles
[x
].fd
< 0) {
857 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, consoles
[x
].p
)) {
858 ast_log(LOG_ERROR
, "Unable to create pipe: %s\n", strerror(errno
));
860 fdprint(s
, "Server failed to create pipe\n");
864 flags
= fcntl(consoles
[x
].p
[1], F_GETFL
);
865 fcntl(consoles
[x
].p
[1], F_SETFL
, flags
| O_NONBLOCK
);
867 consoles
[x
].mute
= ast_opt_mute
;
868 if (ast_pthread_create(&consoles
[x
].t
, &attr
, netconsole
, &consoles
[x
])) {
869 ast_log(LOG_ERROR
, "Unable to spawn thread to handle connection: %s\n", strerror(errno
));
870 close(consoles
[x
].p
[0]);
871 close(consoles
[x
].p
[1]);
873 fdprint(s
, "Server failed to spawn thread\n");
879 if (x
>= AST_MAX_CONNECTS
) {
880 fdprint(s
, "No more connections allowed\n");
881 ast_log(LOG_WARNING
, "No more connections allowed\n");
883 } else if (consoles
[x
].fd
> -1) {
884 if (option_verbose
> 2)
885 ast_verbose(VERBOSE_PREFIX_3
"Remote UNIX connection\n");
892 static int ast_makesocket(void)
894 struct sockaddr_un sunaddr
;
900 for (x
= 0; x
< AST_MAX_CONNECTS
; x
++)
902 unlink(ast_config_AST_SOCKET
);
903 ast_socket
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
904 if (ast_socket
< 0) {
905 ast_log(LOG_WARNING
, "Unable to create control socket: %s\n", strerror(errno
));
908 memset(&sunaddr
, 0, sizeof(sunaddr
));
909 sunaddr
.sun_family
= AF_LOCAL
;
910 ast_copy_string(sunaddr
.sun_path
, ast_config_AST_SOCKET
, sizeof(sunaddr
.sun_path
));
911 res
= bind(ast_socket
, (struct sockaddr
*)&sunaddr
, sizeof(sunaddr
));
913 ast_log(LOG_WARNING
, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET
, strerror(errno
));
918 res
= listen(ast_socket
, 2);
920 ast_log(LOG_WARNING
, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET
, strerror(errno
));
925 ast_register_verbose(network_verboser
);
926 ast_pthread_create(<hread
, NULL
, listener
, NULL
);
928 if (!ast_strlen_zero(ast_config_AST_CTL_OWNER
)) {
930 if ((pw
= getpwnam(ast_config_AST_CTL_OWNER
)) == NULL
) {
931 ast_log(LOG_WARNING
, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER
);
937 if (!ast_strlen_zero(ast_config_AST_CTL_GROUP
)) {
939 if ((grp
= getgrnam(ast_config_AST_CTL_GROUP
)) == NULL
) {
940 ast_log(LOG_WARNING
, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP
);
946 if (chown(ast_config_AST_SOCKET
, uid
, gid
) < 0)
947 ast_log(LOG_WARNING
, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET
, strerror(errno
));
949 if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS
)) {
952 sscanf(ast_config_AST_CTL_PERMISSIONS
, "%o", &p1
);
954 if ((chmod(ast_config_AST_SOCKET
, p
)) < 0)
955 ast_log(LOG_WARNING
, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET
, strerror(errno
));
961 static int ast_tryconnect(void)
963 struct sockaddr_un sunaddr
;
965 ast_consock
= socket(PF_LOCAL
, SOCK_STREAM
, 0);
966 if (ast_consock
< 0) {
967 ast_log(LOG_WARNING
, "Unable to create socket: %s\n", strerror(errno
));
970 memset(&sunaddr
, 0, sizeof(sunaddr
));
971 sunaddr
.sun_family
= AF_LOCAL
;
972 ast_copy_string(sunaddr
.sun_path
, (char *)ast_config_AST_SOCKET
, sizeof(sunaddr
.sun_path
));
973 res
= connect(ast_consock
, (struct sockaddr
*)&sunaddr
, sizeof(sunaddr
));
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
986 SLD: seems to be some pthread activity relating to the printf anyway:
987 which is leading to a deadlock?
989 static void urg_handler(int num
)
992 if (option_debug
> 2)
993 printf("-- Asterisk Urgent handler\n");
995 signal(num
, urg_handler
);
999 static void hup_handler(int num
)
1001 if (option_verbose
> 1)
1002 printf("Received HUP signal -- Reloading configs\n");
1004 execvp(_argv
[0], _argv
);
1005 /* XXX This could deadlock XXX */
1006 ast_module_reload(NULL
);
1007 signal(num
, hup_handler
);
1010 static void child_handler(int sig
)
1012 /* Must not ever ast_log or ast_verbose within signal handler */
1016 * Reap all dead children -- not just one
1018 for (n
= 0; wait4(-1, &status
, WNOHANG
, NULL
) > 0; n
++)
1020 if (n
== 0 && option_debug
)
1021 printf("Huh? Child handler, but nobody there?\n");
1022 signal(sig
, child_handler
);
1025 /*! Set an X-term or screen title */
1026 static void set_title(char *text
)
1028 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1029 fprintf(stdout
, "\033]2;%s\007", text
);
1032 static void set_icon(char *text
)
1034 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1035 fprintf(stdout
, "\033]1;%s\007", text
);
1038 /*! We set ourselves to a high priority, that we might pre-empt everything
1039 else. If your PBX has heavy activity on it, this is a good thing. */
1040 int ast_set_priority(int pri
)
1042 struct sched_param sched
;
1043 memset(&sched
, 0, sizeof(sched
));
1046 sched
.sched_priority
= 10;
1047 if (sched_setscheduler(0, SCHED_RR
, &sched
)) {
1048 ast_log(LOG_WARNING
, "Unable to set high priority\n");
1052 ast_verbose("Set to realtime thread\n");
1054 sched
.sched_priority
= 0;
1055 if (sched_setscheduler(0, SCHED_OTHER
, &sched
)) {
1056 ast_log(LOG_WARNING
, "Unable to set normal priority\n");
1062 if (setpriority(PRIO_PROCESS
, 0, -10) == -1) {
1063 ast_log(LOG_WARNING
, "Unable to set high priority\n");
1067 ast_verbose("Set to high priority\n");
1069 if (setpriority(PRIO_PROCESS
, 0, 0) == -1) {
1070 ast_log(LOG_WARNING
, "Unable to set normal priority\n");
1078 static void ast_run_atexits(void)
1080 struct ast_atexit
*ae
;
1081 AST_LIST_LOCK(&atexits
);
1082 AST_LIST_TRAVERSE(&atexits
, ae
, list
) {
1086 AST_LIST_UNLOCK(&atexits
);
1089 static void quit_handler(int num
, int nice
, int safeshutdown
, int restart
)
1091 char filename
[80] = "";
1094 /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1095 ast_cdr_engine_term();
1099 /* Begin shutdown routine, hanging up active channels */
1100 ast_begin_shutdown(1);
1101 if (option_verbose
&& ast_opt_console
)
1102 ast_verbose("Beginning asterisk %s....\n", restart
? "restart" : "shutdown");
1106 /* Wait up to 15 seconds for all channels to go away */
1109 if (!ast_active_channels())
1113 /* Sleep 1/10 of a second */
1118 ast_begin_shutdown(0);
1119 if (option_verbose
&& ast_opt_console
)
1120 ast_verbose("Waiting for inactivity to perform %s...\n", restart
? "restart" : "halt");
1122 if (!ast_active_channels())
1130 if (!shuttingdown
) {
1131 if (option_verbose
&& ast_opt_console
)
1132 ast_verbose("Asterisk %s cancelled.\n", restart
? "restart" : "shutdown");
1136 if (ast_opt_console
|| ast_opt_remote
) {
1138 snprintf(filename
, sizeof(filename
), "%s/.asterisk_history", getenv("HOME"));
1139 if (!ast_strlen_zero(filename
))
1140 ast_el_write_history(filename
);
1143 if (el_hist
!= NULL
)
1144 history_end(el_hist
);
1147 ast_verbose("Executing last minute cleanups\n");
1149 /* Called on exit */
1150 if (option_verbose
&& ast_opt_console
)
1151 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num
);
1152 else if (option_debug
)
1153 ast_log(LOG_DEBUG
, "Asterisk ending (%d).\n", num
);
1154 manager_event(EVENT_FLAG_SYSTEM
, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart
? "True" : "False");
1155 if (ast_socket
> -1) {
1158 unlink(ast_config_AST_SOCKET
);
1159 pthread_cancel(lthread
);
1161 if (ast_consock
> -1)
1163 if (!ast_opt_remote
)
1164 unlink(ast_config_AST_PID
);
1165 printf(term_quit());
1167 if (option_verbose
|| ast_opt_console
)
1168 ast_verbose("Preparing for Asterisk restart...\n");
1169 /* Mark all FD's for closing on exec */
1170 for (x
=3; x
< 32768; x
++) {
1171 fcntl(x
, F_SETFD
, FD_CLOEXEC
);
1173 if (option_verbose
|| ast_opt_console
)
1174 ast_verbose("Restarting Asterisk NOW...\n");
1180 /* If there is a consolethread running send it a SIGHUP
1181 so it can execvp, otherwise we can do it ourselves */
1182 if ((consolethread
!= AST_PTHREADT_NULL
) && (consolethread
!= pthread_self())) {
1183 pthread_kill(consolethread
, SIGHUP
);
1184 /* Give the signal handler some time to complete */
1187 execvp(_argv
[0], _argv
);
1196 static void __quit_handler(int num
)
1198 quit_handler(num
, 0, 1, 0);
1201 static const char *fix_header(char *outbuf
, int maxout
, const char *s
, char *cmp
)
1204 if (!strncmp(s
, cmp
, strlen(cmp
))) {
1205 c
= s
+ strlen(cmp
);
1206 term_color(outbuf
, cmp
, COLOR_GRAY
, 0, maxout
);
1212 static void console_verboser(const char *s
, int pos
, int replace
, int complete
)
1215 const char *c
= NULL
;
1216 /* Return to the beginning of the line */
1218 fprintf(stdout
, "\r");
1219 if ((c
= fix_header(tmp
, sizeof(tmp
), s
, VERBOSE_PREFIX_4
)) ||
1220 (c
= fix_header(tmp
, sizeof(tmp
), s
, VERBOSE_PREFIX_3
)) ||
1221 (c
= fix_header(tmp
, sizeof(tmp
), s
, VERBOSE_PREFIX_2
)) ||
1222 (c
= fix_header(tmp
, sizeof(tmp
), s
, VERBOSE_PREFIX_1
)))
1226 fputs(c
+ pos
,stdout
);
1228 fputs(s
+ pos
,stdout
);
1231 /* Wake up a poll()ing console */
1232 if (ast_opt_console
&& consolethread
!= AST_PTHREADT_NULL
)
1233 pthread_kill(consolethread
, SIGURG
);
1237 static int ast_all_zeros(char *s
)
1247 static void consolehandler(char *s
)
1251 /* Called when readline data is available */
1252 if (s
&& !ast_all_zeros(s
))
1253 ast_el_add_history(s
);
1254 /* Give the console access to the shell */
1256 /* The real handler for bang */
1259 ast_safe_system(s
+1);
1261 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1263 ast_cli_command(STDOUT_FILENO
, s
);
1265 fprintf(stdout
, "\nUse \"quit\" to exit\n");
1268 static int remoteconsolehandler(char *s
)
1271 /* Called when readline data is available */
1272 if (s
&& !ast_all_zeros(s
))
1273 ast_el_add_history(s
);
1274 /* Give the console access to the shell */
1276 /* The real handler for bang */
1279 ast_safe_system(s
+1);
1281 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1284 if ((strncasecmp(s
, "quit", 4) == 0 || strncasecmp(s
, "exit", 4) == 0) &&
1285 (s
[4] == '\0' || isspace(s
[4]))) {
1286 quit_handler(0, 0, 0, 0);
1290 fprintf(stdout
, "\nUse \"quit\" to exit\n");
1295 static char abort_halt_help
[] =
1296 "Usage: abort shutdown\n"
1297 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1298 " call operations.\n";
1300 static char shutdown_now_help
[] =
1302 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1304 static char shutdown_gracefully_help
[] =
1305 "Usage: stop gracefully\n"
1306 " Causes Asterisk to not accept new calls, and exit when all\n"
1307 " active calls have terminated normally.\n";
1309 static char shutdown_when_convenient_help
[] =
1310 "Usage: stop when convenient\n"
1311 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1313 static char restart_now_help
[] =
1314 "Usage: restart now\n"
1315 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1318 static char restart_gracefully_help
[] =
1319 "Usage: restart gracefully\n"
1320 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1321 " restart when all active calls have ended.\n";
1323 static char restart_when_convenient_help
[] =
1324 "Usage: restart when convenient\n"
1325 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1327 static char bang_help
[] =
1328 "Usage: !<command>\n"
1329 " Executes a given shell command\n";
1331 static char show_warranty_help
[] =
1332 "Usage: show warranty\n"
1333 " Shows the warranty (if any) for this copy of Asterisk.\n";
1335 static char show_license_help
[] =
1336 "Usage: show license\n"
1337 " Shows the license(s) for this copy of Asterisk.\n";
1339 static char version_help
[] =
1340 "Usage: show version\n"
1341 " Shows Asterisk version information.\n";
1343 static int handle_version(int fd
, int argc
, char *argv
[])
1346 return RESULT_SHOWUSAGE
;
1347 ast_cli(fd
, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1348 ASTERISK_VERSION
, ast_build_user
, ast_build_hostname
,
1349 ast_build_machine
, ast_build_os
, ast_build_date
);
1350 return RESULT_SUCCESS
;
1354 static int handle_quit(int fd
, int argc
, char *argv
[])
1357 return RESULT_SHOWUSAGE
;
1358 quit_handler(0, 0, 1, 0);
1359 return RESULT_SUCCESS
;
1363 static int handle_shutdown_now(int fd
, int argc
, char *argv
[])
1366 return RESULT_SHOWUSAGE
;
1367 quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1368 return RESULT_SUCCESS
;
1371 static int handle_shutdown_gracefully(int fd
, int argc
, char *argv
[])
1374 return RESULT_SHOWUSAGE
;
1375 quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1376 return RESULT_SUCCESS
;
1379 static int handle_shutdown_when_convenient(int fd
, int argc
, char *argv
[])
1382 return RESULT_SHOWUSAGE
;
1383 ast_cli(fd
, "Waiting for inactivity to perform halt\n");
1384 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1385 return RESULT_SUCCESS
;
1388 static int handle_restart_now(int fd
, int argc
, char *argv
[])
1391 return RESULT_SHOWUSAGE
;
1392 quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1393 return RESULT_SUCCESS
;
1396 static int handle_restart_gracefully(int fd
, int argc
, char *argv
[])
1399 return RESULT_SHOWUSAGE
;
1400 quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1401 return RESULT_SUCCESS
;
1404 static int handle_restart_when_convenient(int fd
, int argc
, char *argv
[])
1407 return RESULT_SHOWUSAGE
;
1408 ast_cli(fd
, "Waiting for inactivity to perform restart\n");
1409 quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1410 return RESULT_SUCCESS
;
1413 static int handle_abort_halt(int fd
, int argc
, char *argv
[])
1416 return RESULT_SHOWUSAGE
;
1417 ast_cancel_shutdown();
1419 return RESULT_SUCCESS
;
1422 static int handle_bang(int fd
, int argc
, char *argv
[])
1424 return RESULT_SUCCESS
;
1426 static const char *warranty_lines
[] = {
1430 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1431 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n",
1432 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1433 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1434 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1435 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n",
1436 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n",
1437 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1438 "REPAIR OR CORRECTION.\n",
1440 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1441 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1442 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1443 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1444 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1445 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1446 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1447 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1448 "POSSIBILITY OF SUCH DAMAGES.\n",
1451 static int show_warranty(int fd
, int argc
, char *argv
[])
1455 for (x
= 0; x
< sizeof(warranty_lines
) / sizeof(warranty_lines
[0]); x
++)
1456 ast_cli(fd
, (char *) warranty_lines
[x
]);
1458 return RESULT_SUCCESS
;
1461 static const char *license_lines
[] = {
1463 "This program is free software; you can redistribute it and/or modify\n",
1464 "it under the terms of the GNU General Public License version 2 as\n",
1465 "published by the Free Software Foundation.\n",
1467 "This program also contains components licensed under other licenses.\n",
1470 "This program is distributed in the hope that it will be useful,\n",
1471 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1472 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n",
1473 "GNU General Public License for more details.\n",
1475 "You should have received a copy of the GNU General Public License\n",
1476 "along with this program; if not, write to the Free Software\n",
1477 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n",
1480 static int show_license(int fd
, int argc
, char *argv
[])
1484 for (x
= 0; x
< sizeof(license_lines
) / sizeof(license_lines
[0]); x
++)
1485 ast_cli(fd
, (char *) license_lines
[x
]);
1487 return RESULT_SUCCESS
;
1490 #define ASTERISK_PROMPT "*CLI> "
1492 #define ASTERISK_PROMPT2 "%s*CLI> "
1494 static struct ast_cli_entry core_cli
[] = {
1495 { { "abort", "halt", NULL
}, handle_abort_halt
,
1496 "Cancel a running halt", abort_halt_help
},
1497 { { "stop", "now", NULL
}, handle_shutdown_now
,
1498 "Shut down Asterisk immediately", shutdown_now_help
},
1499 { { "stop", "gracefully", NULL
}, handle_shutdown_gracefully
,
1500 "Gracefully shut down Asterisk", shutdown_gracefully_help
},
1501 { { "stop", "when","convenient", NULL
}, handle_shutdown_when_convenient
,
1502 "Shut down Asterisk at empty call volume", shutdown_when_convenient_help
},
1503 { { "restart", "now", NULL
}, handle_restart_now
,
1504 "Restart Asterisk immediately", restart_now_help
},
1505 { { "restart", "gracefully", NULL
}, handle_restart_gracefully
,
1506 "Restart Asterisk gracefully", restart_gracefully_help
},
1507 { { "restart", "when", "convenient", NULL
}, handle_restart_when_convenient
,
1508 "Restart Asterisk at empty call volume", restart_when_convenient_help
},
1509 { { "show", "warranty", NULL
}, show_warranty
,
1510 "Show the warranty (if any) for this copy of Asterisk", show_warranty_help
},
1511 { { "show", "license", NULL
}, show_license
,
1512 "Show the license(s) for this copy of Asterisk", show_license_help
},
1513 { { "show", "version", NULL
}, handle_version
,
1514 "Display version info", version_help
},
1515 { { "!", NULL
}, handle_bang
,
1516 "Execute a shell command", bang_help
},
1517 #if !defined(LOW_MEMORY)
1518 { { "show", "version", "files", NULL
}, handle_show_version_files
,
1519 "Show versions of files used to build Asterisk", show_version_files_help
, complete_show_version_files
},
1520 { { "show", "threads", NULL
}, handle_show_threads
,
1521 "Show running threads", show_threads_help
, NULL
},
1522 { { "show", "profile", NULL
}, handle_show_profile
,
1523 "Show profiling info"},
1524 { { "clear", "profile", NULL
}, handle_show_profile
,
1525 "Clear profiling info"},
1526 #endif /* ! LOW_MEMORY */
1529 static int ast_el_read_char(EditLine
*el
, char *cp
)
1533 struct pollfd fds
[2];
1540 fds
[0].fd
= ast_consock
;
1541 fds
[0].events
= POLLIN
;
1542 if (!ast_opt_exec
) {
1543 fds
[1].fd
= STDIN_FILENO
;
1544 fds
[1].events
= POLLIN
;
1547 res
= poll(fds
, max
, -1);
1551 ast_log(LOG_ERROR
, "poll failed: %s\n", strerror(errno
));
1555 if (!ast_opt_exec
&& fds
[1].revents
) {
1556 num_read
= read(STDIN_FILENO
, cp
, 1);
1562 if (fds
[0].revents
) {
1563 res
= read(ast_consock
, buf
, sizeof(buf
) - 1);
1564 /* if the remote side disappears exit */
1566 fprintf(stderr
, "\nDisconnected from Asterisk server\n");
1567 if (!ast_opt_reconnect
) {
1568 quit_handler(0, 0, 0, 0);
1571 int reconnects_per_second
= 20;
1572 fprintf(stderr
, "Attempting to reconnect for 30 seconds\n");
1573 for (tries
=0; tries
< 30 * reconnects_per_second
; tries
++) {
1574 if (ast_tryconnect()) {
1575 fprintf(stderr
, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second
* tries
);
1576 printf(term_quit());
1580 usleep(1000000 / reconnects_per_second
);
1583 if (tries
>= 30 * reconnects_per_second
) {
1584 fprintf(stderr
, "Failed to reconnect for 30 seconds. Quitting.\n");
1585 quit_handler(0, 0, 0, 0);
1592 if (!ast_opt_exec
&& !lastpos
)
1593 write(STDOUT_FILENO
, "\r", 1);
1594 write(STDOUT_FILENO
, buf
, res
);
1595 if ((buf
[res
-1] == '\n') || (buf
[res
-2] == '\n')) {
1608 static char *cli_prompt(EditLine
*el
)
1610 static char prompt
[200];
1615 if ((pfmt
= getenv("ASTERISK_PROMPT"))) {
1616 char *t
= pfmt
, *p
= prompt
;
1617 memset(prompt
, 0, sizeof(prompt
));
1618 while (*t
!= '\0' && *p
< sizeof(prompt
)) {
1620 char hostname
[MAXHOSTNAMELEN
]="";
1627 int fgcolor
= COLOR_WHITE
, bgcolor
= COLOR_BLACK
;
1631 case 'C': /* color */
1633 if (sscanf(t
, "%d;%d%n", &fgcolor
, &bgcolor
, &i
) == 2) {
1634 strncat(p
, term_color_code(term_code
, fgcolor
, bgcolor
, sizeof(term_code
)),sizeof(prompt
) - strlen(prompt
) - 1);
1636 } else if (sscanf(t
, "%d%n", &fgcolor
, &i
) == 1) {
1637 strncat(p
, term_color_code(term_code
, fgcolor
, 0, sizeof(term_code
)),sizeof(prompt
) - strlen(prompt
) - 1);
1641 /* If the color has been reset correctly, then there's no need to reset it later */
1642 if ((fgcolor
== COLOR_WHITE
) && (bgcolor
== COLOR_BLACK
)) {
1648 case 'd': /* date */
1649 memset(&tm
, 0, sizeof(tm
));
1651 if (localtime_r(&ts
, &tm
)) {
1652 strftime(p
, sizeof(prompt
) - strlen(prompt
), "%Y-%m-%d", &tm
);
1655 case 'h': /* hostname */
1656 if (!gethostname(hostname
, sizeof(hostname
) - 1)) {
1657 strncat(p
, hostname
, sizeof(prompt
) - strlen(prompt
) - 1);
1659 strncat(p
, "localhost", sizeof(prompt
) - strlen(prompt
) - 1);
1662 case 'H': /* short hostname */
1663 if (!gethostname(hostname
, sizeof(hostname
) - 1)) {
1664 for (i
= 0; i
< sizeof(hostname
); i
++) {
1665 if (hostname
[i
] == '.') {
1670 strncat(p
, hostname
, sizeof(prompt
) - strlen(prompt
) - 1);
1672 strncat(p
, "localhost", sizeof(prompt
) - strlen(prompt
) - 1);
1676 case 'l': /* load avg */
1678 if ((LOADAVG
= fopen("/proc/loadavg", "r"))) {
1679 float avg1
, avg2
, avg3
;
1680 int actproc
, totproc
, npid
, which
;
1681 fscanf(LOADAVG
, "%f %f %f %d/%d %d",
1682 &avg1
, &avg2
, &avg3
, &actproc
, &totproc
, &npid
);
1683 if (sscanf(t
, "%d", &which
) == 1) {
1686 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%.2f", avg1
);
1689 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%.2f", avg2
);
1692 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%.2f", avg3
);
1695 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%d/%d", actproc
, totproc
);
1698 snprintf(p
, sizeof(prompt
) - strlen(prompt
), "%d", npid
);
1705 case 's': /* Asterisk system name (from asterisk.conf) */
1706 strncat(p
, ast_config_AST_SYSTEM_NAME
, sizeof(prompt
) - strlen(prompt
) - 1);
1708 case 't': /* time */
1709 memset(&tm
, 0, sizeof(tm
));
1711 if (localtime_r(&ts
, &tm
)) {
1712 strftime(p
, sizeof(prompt
) - strlen(prompt
), "%H:%M:%S", &tm
);
1715 case '#': /* process console or remote? */
1716 if (!ast_opt_remote
) {
1717 strncat(p
, "#", sizeof(prompt
) - strlen(prompt
) - 1);
1719 strncat(p
, ">", sizeof(prompt
) - strlen(prompt
) - 1);
1722 case '%': /* literal % */
1723 strncat(p
, "%", sizeof(prompt
) - strlen(prompt
) - 1);
1725 case '\0': /* % is last character - prevent bug */
1729 while (*p
!= '\0') {
1740 /* Force colors back to normal at end */
1741 term_color_code(term_code
, COLOR_WHITE
, COLOR_BLACK
, sizeof(term_code
));
1742 if (strlen(term_code
) > sizeof(prompt
) - strlen(prompt
)) {
1743 strncat(prompt
+ sizeof(prompt
) - strlen(term_code
) - 1, term_code
, strlen(term_code
));
1745 strncat(p
, term_code
, sizeof(term_code
));
1748 } else if (remotehostname
)
1749 snprintf(prompt
, sizeof(prompt
), ASTERISK_PROMPT2
, remotehostname
);
1751 snprintf(prompt
, sizeof(prompt
), ASTERISK_PROMPT
);
1756 static char **ast_el_strtoarr(char *buf
)
1758 char **match_list
= NULL
, *retstr
;
1759 size_t match_list_len
;
1763 while ( (retstr
= strsep(&buf
, " ")) != NULL
) {
1765 if (!strcmp(retstr
, AST_CLI_COMPLETE_EOF
))
1767 if (matches
+ 1 >= match_list_len
) {
1768 match_list_len
<<= 1;
1769 if (!(match_list
= ast_realloc(match_list
, match_list_len
* sizeof(char *)))) {
1770 /* TODO: Handle memory allocation failure */
1774 match_list
[matches
++] = strdup(retstr
);
1778 return (char **) NULL
;
1780 if (matches
>= match_list_len
) {
1781 if (!(match_list
= ast_realloc(match_list
, (match_list_len
+ 1) * sizeof(char *)))) {
1782 /* TODO: Handle memory allocation failure */
1786 match_list
[matches
] = (char *) NULL
;
1791 static int ast_el_sort_compare(const void *i1
, const void *i2
)
1795 s1
= ((char **)i1
)[0];
1796 s2
= ((char **)i2
)[0];
1798 return strcasecmp(s1
, s2
);
1801 static int ast_cli_display_match_list(char **matches
, int len
, int max
)
1803 int i
, idx
, limit
, count
;
1804 int screenwidth
= 0;
1805 int numoutput
= 0, numoutputline
= 0;
1807 screenwidth
= ast_get_termcols(STDOUT_FILENO
);
1809 /* find out how many entries can be put on one line, with two spaces between strings */
1810 limit
= screenwidth
/ (max
+ 2);
1814 /* how many lines of output */
1815 count
= len
/ limit
;
1816 if (count
* limit
< len
)
1821 qsort(&matches
[0], (size_t)(len
), sizeof(char *), ast_el_sort_compare
);
1823 for (; count
> 0; count
--) {
1825 for (i
=0; i
< limit
&& matches
[idx
]; i
++, idx
++) {
1827 /* Don't print dupes */
1828 if ( (matches
[idx
+1] != NULL
&& strcmp(matches
[idx
], matches
[idx
+1]) == 0 ) ) {
1831 matches
[idx
] = NULL
;
1837 fprintf(stdout
, "%-*s ", max
, matches
[idx
]);
1839 matches
[idx
] = NULL
;
1841 if (numoutputline
> 0)
1842 fprintf(stdout
, "\n");
1849 static char *cli_complete(EditLine
*el
, int ch
)
1855 int retval
= CC_ERROR
;
1859 LineInfo
*lf
= (LineInfo
*)el_line(el
);
1861 *(char *)lf
->cursor
= '\0';
1862 ptr
= (char *)lf
->cursor
;
1864 while (ptr
> lf
->buffer
) {
1865 if (isspace(*ptr
)) {
1873 len
= lf
->cursor
- ptr
;
1875 if (ast_opt_remote
) {
1876 snprintf(buf
, sizeof(buf
),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf
->buffer
, ptr
);
1877 fdprint(ast_consock
, buf
);
1878 res
= read(ast_consock
, buf
, sizeof(buf
));
1880 nummatches
= atoi(buf
);
1882 if (nummatches
> 0) {
1884 int mlen
= 0, maxmbuf
= 2048;
1885 /* Start with a 2048 byte buffer */
1886 if (!(mbuf
= ast_malloc(maxmbuf
)))
1887 return (char *)(CC_ERROR
);
1888 snprintf(buf
, sizeof(buf
),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf
->buffer
, ptr
);
1889 fdprint(ast_consock
, buf
);
1892 while (!strstr(mbuf
, AST_CLI_COMPLETE_EOF
) && res
!= -1) {
1893 if (mlen
+ 1024 > maxmbuf
) {
1894 /* Every step increment buffer 1024 bytes */
1896 if (!(mbuf
= ast_realloc(mbuf
, maxmbuf
)))
1897 return (char *)(CC_ERROR
);
1899 /* Only read 1024 bytes at a time */
1900 res
= read(ast_consock
, mbuf
+ mlen
, 1024);
1906 matches
= ast_el_strtoarr(mbuf
);
1909 matches
= (char **) NULL
;
1911 char **p
, *oldbuf
=NULL
;
1913 matches
= ast_cli_completion_matches((char *)lf
->buffer
,ptr
);
1914 for (p
= matches
; p
&& *p
; p
++) {
1915 if (!oldbuf
|| strcmp(*p
,oldbuf
))
1923 int matches_num
, maxlen
, match_len
;
1925 if (matches
[0][0] != '\0') {
1926 el_deletestr(el
, (int) len
);
1927 el_insertstr(el
, matches
[0]);
1928 retval
= CC_REFRESH
;
1931 if (nummatches
== 1) {
1932 /* Found an exact match */
1933 el_insertstr(el
, " ");
1934 retval
= CC_REFRESH
;
1936 /* Must be more than one match */
1937 for (i
=1, maxlen
=0; matches
[i
]; i
++) {
1938 match_len
= strlen(matches
[i
]);
1939 if (match_len
> maxlen
)
1942 matches_num
= i
- 1;
1943 if (matches_num
>1) {
1944 fprintf(stdout
, "\n");
1945 ast_cli_display_match_list(matches
, nummatches
, maxlen
);
1946 retval
= CC_REDISPLAY
;
1948 el_insertstr(el
," ");
1949 retval
= CC_REFRESH
;
1955 return (char *)(long)retval
;
1958 static int ast_el_initialize(void)
1961 char *editor
= getenv("AST_EDITOR");
1965 if (el_hist
!= NULL
)
1966 history_end(el_hist
);
1968 el
= el_init("asterisk", stdin
, stdout
, stderr
);
1969 el_set(el
, EL_PROMPT
, cli_prompt
);
1971 el_set(el
, EL_EDITMODE
, 1);
1972 el_set(el
, EL_EDITOR
, editor
? editor
: "emacs");
1973 el_hist
= history_init();
1974 if (!el
|| !el_hist
)
1977 /* setup history with 100 entries */
1978 history(el_hist
, &ev
, H_SETSIZE
, 100);
1980 el_set(el
, EL_HIST
, history
, el_hist
);
1982 el_set(el
, EL_ADDFN
, "ed-complete", "Complete argument", cli_complete
);
1983 /* Bind <tab> to command completion */
1984 el_set(el
, EL_BIND
, "^I", "ed-complete", NULL
);
1985 /* Bind ? to command completion */
1986 el_set(el
, EL_BIND
, "?", "ed-complete", NULL
);
1987 /* Bind ^D to redisplay */
1988 el_set(el
, EL_BIND
, "^D", "ed-redisplay", NULL
);
1993 static int ast_el_add_history(char *buf
)
1997 if (el_hist
== NULL
|| el
== NULL
)
1998 ast_el_initialize();
1999 if (strlen(buf
) > 256)
2001 return (history(el_hist
, &ev
, H_ENTER
, buf
));
2004 static int ast_el_write_history(char *filename
)
2008 if (el_hist
== NULL
|| el
== NULL
)
2009 ast_el_initialize();
2011 return (history(el_hist
, &ev
, H_SAVE
, filename
));
2014 static int ast_el_read_history(char *filename
)
2020 if (el_hist
== NULL
|| el
== NULL
)
2021 ast_el_initialize();
2023 if ((f
= fopen(filename
, "r")) == NULL
)
2027 fgets(buf
, sizeof(buf
), f
);
2028 if (!strcmp(buf
, "_HiStOrY_V2_\n"))
2030 if (ast_all_zeros(buf
))
2032 if ((ret
= ast_el_add_history(buf
)) == -1)
2040 static void ast_remotecontrol(char * data
)
2044 char filename
[80] = "";
2050 char *stringp
= NULL
;
2055 read(ast_consock
, buf
, sizeof(buf
));
2057 write(ast_consock
, data
, strlen(data
) + 1);
2059 hostname
= strsep(&stringp
, "/");
2060 cpid
= strsep(&stringp
, "/");
2061 version
= strsep(&stringp
, "\n");
2063 version
= "<Version Unknown>";
2065 strsep(&stringp
, ".");
2070 snprintf(tmp
, sizeof(tmp
), "set verbose atleast %d", option_verbose
);
2071 fdprint(ast_consock
, tmp
);
2072 snprintf(tmp
, sizeof(tmp
), "set debug atleast %d", option_debug
);
2073 fdprint(ast_consock
, tmp
);
2075 snprintf(tmp
, sizeof(tmp
), "log and verbose output currently muted ('logger unmute' to unmute)");
2076 fdprint(ast_consock
, tmp
);
2078 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version
, hostname
, pid
);
2079 remotehostname
= hostname
;
2081 snprintf(filename
, sizeof(filename
), "%s/.asterisk_history", getenv("HOME"));
2082 if (el_hist
== NULL
|| el
== NULL
)
2083 ast_el_initialize();
2085 el_set(el
, EL_GETCFN
, ast_el_read_char
);
2087 if (!ast_strlen_zero(filename
))
2088 ast_el_read_history(filename
);
2090 if (ast_opt_exec
&& data
) { /* hack to print output then exit if asterisk -rx is used */
2093 struct pollfd fds
[0];
2094 fds
[0].fd
= ast_consock
;
2095 fds
[0].events
= POLLIN
;
2097 while (poll(fds
, 1, 100) > 0) {
2098 ast_el_read_char(el
, &tempchar
);
2101 while (!ast_el_read_char(el
, &tempchar
));
2106 ebuf
= (char *)el_gets(el
, &num
);
2108 if (!ast_strlen_zero(ebuf
)) {
2109 if (ebuf
[strlen(ebuf
)-1] == '\n')
2110 ebuf
[strlen(ebuf
)-1] = '\0';
2111 if (!remoteconsolehandler(ebuf
)) {
2112 res
= write(ast_consock
, ebuf
, strlen(ebuf
) + 1);
2114 ast_log(LOG_WARNING
, "Unable to write: %s\n", strerror(errno
));
2120 printf("\nDisconnected from Asterisk server\n");
2123 static int show_version(void)
2125 printf("Asterisk " ASTERISK_VERSION
"\n");
2129 static int show_cli_help(void) {
2130 printf("Asterisk " ASTERISK_VERSION
", Copyright (C) 1999 - 2006, Digium, Inc. and others.\n");
2131 printf("Usage: asterisk [OPTIONS]\n");
2132 printf("Valid Options:\n");
2133 printf(" -V Display version number and exit\n");
2134 printf(" -C <configfile> Use an alternate configuration file\n");
2135 printf(" -G <group> Run as a group other than the caller\n");
2136 printf(" -U <user> Run as a user other than the caller\n");
2137 printf(" -c Provide console CLI\n");
2138 printf(" -d Enable extra debugging\n");
2139 printf(" -f Do not fork\n");
2140 printf(" -g Dump core in case of a crash\n");
2141 printf(" -h This help screen\n");
2142 printf(" -i Initialize crypto keys at startup\n");
2143 printf(" -I Enable internal timing if Zaptel timer is available\n");
2144 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
2145 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
2146 printf(" -m Mute the console from debugging and verbose output\n");
2147 printf(" -n Disable console colorization\n");
2148 printf(" -p Run as pseudo-realtime thread\n");
2149 printf(" -q Quiet mode (suppress output)\n");
2150 printf(" -r Connect to Asterisk on this machine\n");
2151 printf(" -R Connect to Asterisk, and attempt to reconnect if disconnected\n");
2152 printf(" -t Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
2153 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
2154 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
2155 printf(" -x <cmd> Execute command <cmd> (only valid with -r)\n");
2160 static void ast_readconfig(void)
2162 struct ast_config
*cfg
;
2163 struct ast_variable
*v
;
2164 char *config
= AST_CONFIG_FILE
;
2166 if (ast_opt_override_config
) {
2167 cfg
= ast_config_load(ast_config_AST_CONFIG_FILE
);
2169 ast_log(LOG_WARNING
, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE
);
2171 cfg
= ast_config_load(config
);
2174 /* init with buildtime config */
2175 ast_copy_string(ast_config_AST_CONFIG_DIR
, AST_CONFIG_DIR
, sizeof(ast_config_AST_CONFIG_DIR
));
2176 ast_copy_string(ast_config_AST_SPOOL_DIR
, AST_SPOOL_DIR
, sizeof(ast_config_AST_SPOOL_DIR
));
2177 ast_copy_string(ast_config_AST_MODULE_DIR
, AST_MODULE_DIR
, sizeof(ast_config_AST_MODULE_DIR
));
2178 snprintf(ast_config_AST_MONITOR_DIR
, sizeof(ast_config_AST_MONITOR_DIR
) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR
);
2179 ast_copy_string(ast_config_AST_VAR_DIR
, AST_VAR_DIR
, sizeof(ast_config_AST_VAR_DIR
));
2180 ast_copy_string(ast_config_AST_DATA_DIR
, AST_DATA_DIR
, sizeof(ast_config_AST_DATA_DIR
));
2181 ast_copy_string(ast_config_AST_LOG_DIR
, AST_LOG_DIR
, sizeof(ast_config_AST_LOG_DIR
));
2182 ast_copy_string(ast_config_AST_AGI_DIR
, AST_AGI_DIR
, sizeof(ast_config_AST_AGI_DIR
));
2183 ast_copy_string(ast_config_AST_DB
, AST_DB
, sizeof(ast_config_AST_DB
));
2184 ast_copy_string(ast_config_AST_KEY_DIR
, AST_KEY_DIR
, sizeof(ast_config_AST_KEY_DIR
));
2185 ast_copy_string(ast_config_AST_PID
, AST_PID
, sizeof(ast_config_AST_PID
));
2186 ast_copy_string(ast_config_AST_SOCKET
, AST_SOCKET
, sizeof(ast_config_AST_SOCKET
));
2187 ast_copy_string(ast_config_AST_RUN_DIR
, AST_RUN_DIR
, sizeof(ast_config_AST_RUN_DIR
));
2189 /* no asterisk.conf? no problem, use buildtime config! */
2193 v
= ast_variable_browse(cfg
, "files");
2195 if (!strcasecmp(v
->name
, "astctlpermissions")) {
2196 ast_copy_string(ast_config_AST_CTL_PERMISSIONS
, v
->value
, sizeof(ast_config_AST_CTL_PERMISSIONS
));
2197 } else if (!strcasecmp(v
->name
, "astctlowner")) {
2198 ast_copy_string(ast_config_AST_CTL_OWNER
, v
->value
, sizeof(ast_config_AST_CTL_OWNER
));
2199 } else if (!strcasecmp(v
->name
, "astctlgroup")) {
2200 ast_copy_string(ast_config_AST_CTL_GROUP
, v
->value
, sizeof(ast_config_AST_CTL_GROUP
));
2201 } else if (!strcasecmp(v
->name
, "astctl")) {
2202 ast_copy_string(ast_config_AST_CTL
, v
->value
, sizeof(ast_config_AST_CTL
));
2206 v
= ast_variable_browse(cfg
, "directories");
2208 if (!strcasecmp(v
->name
, "astetcdir")) {
2209 ast_copy_string(ast_config_AST_CONFIG_DIR
, v
->value
, sizeof(ast_config_AST_CONFIG_DIR
));
2210 } else if (!strcasecmp(v
->name
, "astspooldir")) {
2211 ast_copy_string(ast_config_AST_SPOOL_DIR
, v
->value
, sizeof(ast_config_AST_SPOOL_DIR
));
2212 snprintf(ast_config_AST_MONITOR_DIR
, sizeof(ast_config_AST_MONITOR_DIR
) - 1, "%s/monitor", v
->value
);
2213 } else if (!strcasecmp(v
->name
, "astvarlibdir")) {
2214 ast_copy_string(ast_config_AST_VAR_DIR
, v
->value
, sizeof(ast_config_AST_VAR_DIR
));
2215 snprintf(ast_config_AST_DB
, sizeof(ast_config_AST_DB
), "%s/astdb", v
->value
);
2216 } else if (!strcasecmp(v
->name
, "astdatadir")) {
2217 ast_copy_string(ast_config_AST_DATA_DIR
, v
->value
, sizeof(ast_config_AST_DATA_DIR
));
2218 snprintf(ast_config_AST_KEY_DIR
, sizeof(ast_config_AST_KEY_DIR
), "%s/keys", v
->value
);
2219 } else if (!strcasecmp(v
->name
, "astlogdir")) {
2220 ast_copy_string(ast_config_AST_LOG_DIR
, v
->value
, sizeof(ast_config_AST_LOG_DIR
));
2221 } else if (!strcasecmp(v
->name
, "astagidir")) {
2222 ast_copy_string(ast_config_AST_AGI_DIR
, v
->value
, sizeof(ast_config_AST_AGI_DIR
));
2223 } else if (!strcasecmp(v
->name
, "astrundir")) {
2224 snprintf(ast_config_AST_PID
, sizeof(ast_config_AST_PID
), "%s/%s", v
->value
, "asterisk.pid");
2225 snprintf(ast_config_AST_SOCKET
, sizeof(ast_config_AST_SOCKET
), "%s/%s", v
->value
, ast_config_AST_CTL
);
2226 ast_copy_string(ast_config_AST_RUN_DIR
, v
->value
, sizeof(ast_config_AST_RUN_DIR
));
2227 } else if (!strcasecmp(v
->name
, "astmoddir")) {
2228 ast_copy_string(ast_config_AST_MODULE_DIR
, v
->value
, sizeof(ast_config_AST_MODULE_DIR
));
2229 } else if (!strcasecmp(v
->name
, "languageprefix")) {
2230 ast_language_is_prefix
= ast_true(v
->value
);
2234 v
= ast_variable_browse(cfg
, "options");
2236 /* verbose level (-v at startup) */
2237 if (!strcasecmp(v
->name
, "verbose")) {
2238 option_verbose
= atoi(v
->value
);
2239 /* whether or not to force timestamping. (-T at startup) */
2240 } else if (!strcasecmp(v
->name
, "timestamp")) {
2241 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_TIMESTAMP
);
2242 /* whether or not to support #exec in config files */
2243 } else if (!strcasecmp(v
->name
, "execincludes")) {
2244 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_EXEC_INCLUDES
);
2245 /* debug level (-d at startup) */
2246 } else if (!strcasecmp(v
->name
, "debug")) {
2248 if (sscanf(v
->value
, "%d", &option_debug
) != 1) {
2249 option_debug
= ast_true(v
->value
);
2251 /* Disable forking (-f at startup) */
2252 } else if (!strcasecmp(v
->name
, "nofork")) {
2253 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_NO_FORK
);
2254 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2255 } else if (!strcasecmp(v
->name
, "alwaysfork")) {
2256 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_ALWAYS_FORK
);
2257 /* Run quietly (-q at startup ) */
2258 } else if (!strcasecmp(v
->name
, "quiet")) {
2259 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_QUIET
);
2260 /* Run as console (-c at startup, implies nofork) */
2261 } else if (!strcasecmp(v
->name
, "console")) {
2262 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_CONSOLE
);
2263 /* Run with high priority if the O/S permits (-p at startup) */
2264 } else if (!strcasecmp(v
->name
, "highpriority")) {
2265 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_HIGH_PRIORITY
);
2266 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2267 } else if (!strcasecmp(v
->name
, "initcrypto")) {
2268 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_INIT_KEYS
);
2269 /* Disable ANSI colors for console (-c at startup) */
2270 } else if (!strcasecmp(v
->name
, "nocolor")) {
2271 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_NO_COLOR
);
2272 /* Disable some usage warnings for picky people :p */
2273 } else if (!strcasecmp(v
->name
, "dontwarn")) {
2274 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_DONT_WARN
);
2275 /* Dump core in case of crash (-g) */
2276 } else if (!strcasecmp(v
->name
, "dumpcore")) {
2277 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_DUMP_CORE
);
2278 /* Cache recorded sound files to another directory during recording */
2279 } else if (!strcasecmp(v
->name
, "cache_record_files")) {
2280 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_CACHE_RECORD_FILES
);
2281 /* Specify cache directory */
2282 } else if (!strcasecmp(v
->name
, "record_cache_dir")) {
2283 ast_copy_string(record_cache_dir
, v
->value
, AST_CACHE_DIR_LEN
);
2284 /* Build transcode paths via SLINEAR, instead of directly */
2285 } else if (!strcasecmp(v
->name
, "transcode_via_sln")) {
2286 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_TRANSCODE_VIA_SLIN
);
2287 /* Transmit SLINEAR silence while a channel is being recorded */
2288 } else if (!strcasecmp(v
->name
, "transmit_silence_during_record")) {
2289 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_TRANSMIT_SILENCE
);
2290 /* Enable internal timing */
2291 } else if (!strcasecmp(v
->name
, "internal_timing")) {
2292 ast_set2_flag(&ast_options
, ast_true(v
->value
), AST_OPT_FLAG_INTERNAL_TIMING
);
2293 } else if (!strcasecmp(v
->name
, "maxcalls")) {
2294 if ((sscanf(v
->value
, "%d", &option_maxcalls
) != 1) || (option_maxcalls
< 0)) {
2295 option_maxcalls
= 0;
2297 } else if (!strcasecmp(v
->name
, "maxload")) {
2300 if (getloadavg(test
, 1) == -1) {
2301 ast_log(LOG_ERROR
, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2302 option_maxload
= 0.0;
2303 } else if ((sscanf(v
->value
, "%lf", &option_maxload
) != 1) || (option_maxload
< 0.0)) {
2304 option_maxload
= 0.0;
2306 /* What user to run as */
2307 } else if (!strcasecmp(v
->name
, "runuser")) {
2308 ast_copy_string(ast_config_AST_RUN_USER
, v
->value
, sizeof(ast_config_AST_RUN_USER
));
2309 /* What group to run as */
2310 } else if (!strcasecmp(v
->name
, "rungroup")) {
2311 ast_copy_string(ast_config_AST_RUN_GROUP
, v
->value
, sizeof(ast_config_AST_RUN_GROUP
));
2312 } else if (!strcasecmp(v
->name
, "systemname")) {
2313 ast_copy_string(ast_config_AST_SYSTEM_NAME
, v
->value
, sizeof(ast_config_AST_SYSTEM_NAME
));
2317 ast_config_destroy(cfg
);
2320 int main(int argc
, char *argv
[])
2323 char filename
[80] = "";
2324 char hostname
[MAXHOSTNAMELEN
] = "";
2331 int is_child_of_nonroot
= 0;
2333 char *runuser
= NULL
, *rungroup
= NULL
;
2335 /* Remember original args for restart */
2336 if (argc
> sizeof(_argv
) / sizeof(_argv
[0]) - 1) {
2337 fprintf(stderr
, "Truncating argument size to %d\n", (int)(sizeof(_argv
) / sizeof(_argv
[0])) - 1);
2338 argc
= sizeof(_argv
) / sizeof(_argv
[0]) - 1;
2340 for (x
=0; x
<argc
; x
++)
2344 /* if the progname is rasterisk consider it a remote console */
2345 if (argv
[0] && (strstr(argv
[0], "rasterisk")) != NULL
) {
2346 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
| AST_OPT_FLAG_REMOTE
);
2348 if (gethostname(hostname
, sizeof(hostname
)-1))
2349 ast_copy_string(hostname
, "<Unknown>", sizeof(hostname
));
2350 ast_mainpid
= getpid();
2354 ast_builtins_init();
2357 /* When Asterisk restarts after it has dropped the root privileges,
2358 * it can't issue setuid(), setgid(), setgroups() or set_priority()
2360 if (getenv("ASTERISK_ALREADY_NONROOT"))
2361 is_child_of_nonroot
=1;
2363 snprintf(filename
, sizeof(filename
), "%s/.asterisk_history", getenv("HOME"));
2364 /* Check for options */
2365 while ((c
= getopt(argc
, argv
, "mtThfdvVqprRgciInx:U:G:C:L:M:")) != -1) {
2368 ast_set_flag(&ast_options
, AST_OPT_FLAG_ALWAYS_FORK
);
2372 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
);
2375 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
| AST_OPT_FLAG_CONSOLE
);
2378 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
);
2381 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_COLOR
);
2384 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
| AST_OPT_FLAG_REMOTE
);
2387 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
| AST_OPT_FLAG_REMOTE
| AST_OPT_FLAG_RECONNECT
);
2390 ast_set_flag(&ast_options
, AST_OPT_FLAG_HIGH_PRIORITY
);
2394 ast_set_flag(&ast_options
, AST_OPT_FLAG_NO_FORK
);
2397 ast_set_flag(&ast_options
, AST_OPT_FLAG_MUTE
);
2400 if ((sscanf(optarg
, "%d", &option_maxcalls
) != 1) || (option_maxcalls
< 0))
2401 option_maxcalls
= 0;
2404 if ((sscanf(optarg
, "%lf", &option_maxload
) != 1) || (option_maxload
< 0.0))
2405 option_maxload
= 0.0;
2408 ast_set_flag(&ast_options
, AST_OPT_FLAG_QUIET
);
2411 ast_set_flag(&ast_options
, AST_OPT_FLAG_CACHE_RECORD_FILES
);
2414 ast_set_flag(&ast_options
, AST_OPT_FLAG_TIMESTAMP
);
2417 ast_set_flag(&ast_options
, AST_OPT_FLAG_EXEC
);
2421 ast_copy_string(ast_config_AST_CONFIG_FILE
, optarg
, sizeof(ast_config_AST_CONFIG_FILE
));
2422 ast_set_flag(&ast_options
, AST_OPT_FLAG_OVERRIDE_CONFIG
);
2425 ast_set_flag(&ast_options
, AST_OPT_FLAG_INTERNAL_TIMING
);
2428 ast_set_flag(&ast_options
, AST_OPT_FLAG_INIT_KEYS
);
2431 ast_set_flag(&ast_options
, AST_OPT_FLAG_DUMP_CORE
);
2450 if (ast_opt_always_fork
&& (ast_opt_remote
|| ast_opt_console
)) {
2451 ast_log(LOG_WARNING
, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2452 ast_clear_flag(&ast_options
, AST_OPT_FLAG_ALWAYS_FORK
);
2455 /* For remote connections, change the name of the remote connection.
2456 * We do this for the benefit of init scripts (which need to know if/when
2457 * the main asterisk process has died yet). */
2458 if (ast_opt_remote
) {
2459 strcpy(argv
[0], "rasterisk");
2460 for (x
= 1; x
< argc
; x
++) {
2461 argv
[x
] = argv
[0] + 10;
2465 if (ast_opt_console
&& !option_verbose
)
2466 ast_verbose("[ Reading Master Configuration ]");
2469 if (ast_opt_dump_core
) {
2471 memset(&l
, 0, sizeof(l
));
2472 l
.rlim_cur
= RLIM_INFINITY
;
2473 l
.rlim_max
= RLIM_INFINITY
;
2474 if (setrlimit(RLIMIT_CORE
, &l
)) {
2475 ast_log(LOG_WARNING
, "Unable to disable core size resource limit: %s\n", strerror(errno
));
2479 if ((!rungroup
) && !ast_strlen_zero(ast_config_AST_RUN_GROUP
))
2480 rungroup
= ast_config_AST_RUN_GROUP
;
2481 if ((!runuser
) && !ast_strlen_zero(ast_config_AST_RUN_USER
))
2482 runuser
= ast_config_AST_RUN_USER
;
2486 if (!is_child_of_nonroot
)
2487 ast_set_priority(ast_opt_high_priority
);
2489 if (!is_child_of_nonroot
&& rungroup
) {
2491 gr
= getgrnam(rungroup
);
2493 ast_log(LOG_WARNING
, "No such group '%s'!\n", rungroup
);
2496 if (setgid(gr
->gr_gid
)) {
2497 ast_log(LOG_WARNING
, "Unable to setgid to %d (%s)\n", (int)gr
->gr_gid
, rungroup
);
2500 if (setgroups(0, NULL
)) {
2501 ast_log(LOG_WARNING
, "Unable to drop unneeded groups\n");
2505 ast_verbose("Running as group '%s'\n", rungroup
);
2508 if (!is_child_of_nonroot
&& runuser
) {
2510 pw
= getpwnam(runuser
);
2512 ast_log(LOG_WARNING
, "No such user '%s'!\n", runuser
);
2516 if (setgid(pw
->pw_gid
)) {
2517 ast_log(LOG_WARNING
, "Unable to setgid to %d!\n", (int)pw
->pw_gid
);
2520 if (initgroups(pw
->pw_name
, pw
->pw_gid
)) {
2521 ast_log(LOG_WARNING
, "Unable to init groups for '%s'\n", runuser
);
2525 if (setuid(pw
->pw_uid
)) {
2526 ast_log(LOG_WARNING
, "Unable to setuid to %d (%s)\n", (int)pw
->pw_uid
, runuser
);
2529 setenv("ASTERISK_ALREADY_NONROOT", "yes", 1);
2531 ast_verbose("Running as user '%s'\n", runuser
);
2534 #endif /* __CYGWIN__ */
2537 if (geteuid() && ast_opt_dump_core
) {
2538 if (prctl(PR_SET_DUMPABLE
, 1, 0, 0, 0) < 0) {
2539 ast_log(LOG_WARNING
, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno
));
2548 if (ast_opt_console
&& !option_verbose
)
2549 ast_verbose("[ Initializing Custom Configuration Options ]");
2550 /* custom config setup */
2551 register_config_cli();
2554 if (ast_opt_console
) {
2555 if (el_hist
== NULL
|| el
== NULL
)
2556 ast_el_initialize();
2558 if (!ast_strlen_zero(filename
))
2559 ast_el_read_history(filename
);
2562 if (ast_tryconnect()) {
2563 /* One is already running */
2564 if (ast_opt_remote
) {
2566 ast_remotecontrol(xarg
);
2567 quit_handler(0, 0, 0, 0);
2570 printf(term_quit());
2571 ast_register_verbose(console_verboser
);
2573 ast_remotecontrol(NULL
);
2574 quit_handler(0, 0, 0, 0);
2577 ast_log(LOG_ERROR
, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET
);
2578 printf(term_quit());
2581 } else if (ast_opt_remote
|| ast_opt_exec
) {
2582 ast_log(LOG_ERROR
, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET
);
2583 printf(term_quit());
2586 /* Blindly write pid file since we couldn't connect */
2587 unlink(ast_config_AST_PID
);
2588 f
= fopen(ast_config_AST_PID
, "w");
2590 fprintf(f
, "%ld\n", (long)getpid());
2593 ast_log(LOG_WARNING
, "Unable to open pid file '%s': %s\n", ast_config_AST_PID
, strerror(errno
));
2595 if (ast_opt_always_fork
|| !ast_opt_no_fork
) {
2597 ast_mainpid
= getpid();
2598 /* Blindly re-write pid file since we are forking */
2599 unlink(ast_config_AST_PID
);
2600 f
= fopen(ast_config_AST_PID
, "w");
2602 fprintf(f
, "%ld\n", (long)ast_mainpid
);
2605 ast_log(LOG_WARNING
, "Unable to open pid file '%s': %s\n", ast_config_AST_PID
, strerror(errno
));
2608 /* Test recursive mutex locking. */
2609 if (test_for_thread_safety())
2610 ast_verbose("Warning! Asterisk is not thread safe.\n");
2614 sigaddset(&sigs
, SIGHUP
);
2615 sigaddset(&sigs
, SIGTERM
);
2616 sigaddset(&sigs
, SIGINT
);
2617 sigaddset(&sigs
, SIGPIPE
);
2618 sigaddset(&sigs
, SIGWINCH
);
2619 pthread_sigmask(SIG_BLOCK
, &sigs
, NULL
);
2620 if (ast_opt_console
|| option_verbose
|| ast_opt_remote
)
2621 ast_register_verbose(console_verboser
);
2622 /* Print a welcome message if desired */
2623 if (option_verbose
|| ast_opt_console
) {
2626 if (ast_opt_console
&& !option_verbose
)
2627 ast_verbose("[ Booting...");
2629 signal(SIGURG
, urg_handler
);
2630 signal(SIGINT
, __quit_handler
);
2631 signal(SIGTERM
, __quit_handler
);
2632 signal(SIGHUP
, hup_handler
);
2633 signal(SIGCHLD
, child_handler
);
2634 signal(SIGPIPE
, SIG_IGN
);
2636 /* ensure that the random number generators are seeded with a different value every time
2639 srand((unsigned int) getpid() + (unsigned int) time(NULL
));
2640 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL
), randompool
, sizeof(randompool
));
2642 if (init_logger()) {
2643 printf(term_quit());
2646 if (dnsmgr_init()) {
2647 printf(term_quit());
2650 /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2651 if (load_modules(1)) {
2652 printf(term_quit());
2656 ast_channels_init();
2657 if (init_manager()) {
2658 printf(term_quit());
2661 if (ast_cdr_engine_init()) {
2662 printf(term_quit());
2665 if (ast_device_state_engine_init()) {
2666 printf(term_quit());
2671 if (ast_image_init()) {
2672 printf(term_quit());
2675 if (ast_file_init()) {
2676 printf(term_quit());
2680 printf(term_quit());
2683 if (load_modules(0)) {
2684 printf(term_quit());
2687 if (init_framer()) {
2688 printf(term_quit());
2692 printf(term_quit());
2695 if (ast_enum_init()) {
2696 printf(term_quit());
2700 dnsmgr_start_refresh();
2703 /* This should no longer be necessary */
2704 /* sync cust config and reload some internals in case a custom config handler binded to them */
2705 read_ast_cust_config();
2712 /* We might have the option of showing a console, but for now just
2714 if (ast_opt_console
&& !option_verbose
)
2715 ast_verbose(" ]\n");
2716 if (option_verbose
|| ast_opt_console
)
2717 ast_verbose(term_color(tmp
, "Asterisk Ready.\n", COLOR_BRWHITE
, COLOR_BLACK
, sizeof(tmp
)));
2718 if (ast_opt_no_fork
)
2719 consolethread
= pthread_self();
2720 ast_set_flag(&ast_options
, AST_OPT_FLAG_FULLY_BOOTED
);
2721 pthread_sigmask(SIG_UNBLOCK
, &sigs
, NULL
);
2722 #ifdef __AST_DEBUG_MALLOC
2725 time(&ast_startuptime
);
2726 ast_cli_register_multiple(core_cli
, sizeof(core_cli
) / sizeof(core_cli
[0]));
2727 if (ast_opt_console
) {
2728 /* Console stuff now... */
2729 /* Register our quit function */
2731 set_icon("Asterisk");
2732 snprintf(title
, sizeof(title
), "Asterisk Console on '%s' (pid %ld)", hostname
, (long)ast_mainpid
);
2736 buf
= (char *)el_gets(el
, &num
);
2738 if (buf
[strlen(buf
)-1] == '\n')
2739 buf
[strlen(buf
)-1] = '\0';
2741 consolehandler((char *)buf
);
2743 if (write(STDOUT_FILENO
, "\nUse EXIT or QUIT to exit the asterisk console\n",
2744 strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2745 /* Whoa, stdout disappeared from under us... Make /dev/null's */
2747 fd
= open("/dev/null", O_RDWR
);
2749 dup2(fd
, STDOUT_FILENO
);
2750 dup2(fd
, STDIN_FILENO
);
2752 ast_log(LOG_WARNING
, "Failed to open /dev/null to recover from dead console. Bad things will happen!\n");
2760 for(;;) { /* apparently needed for the MACos */
2761 struct pollfd p
= { -1 /* no descriptor */, 0, 0 };