d5247afe8ea13c1c6e1683de455748e3254398b7
[asterisk/asterisk.git] / main / asterisk.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2008, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
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.
13  *
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.
17  */
18
19
20 /* Doxygenified Copyright Header */
21 /*!
22  * \mainpage Asterisk -- An Open Source Telephony Toolkit
23  *
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
28  * \arg \ref DevDoc 
29  * \arg \ref ConfigFiles
30  *
31  * \section copyright Copyright and author
32  *
33  * Copyright (C) 1999 - 2008, Digium, Inc.
34  * Asterisk is a trademark registered by Digium, Inc.
35  *
36  * \author Mark Spencer <markster@digium.com>
37  * Also see \ref AstCREDITS
38  *
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.
45  *
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.
49  *
50  * \verbinclude LICENSE
51  *
52  */
53
54 /*! \file
55   \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
56   of PBX core functions and CLI interface.
57   
58  */
59
60 #include "asterisk.h"
61
62 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
63
64 #include "asterisk/_private.h"
65
66 #undef sched_setscheduler
67 #undef setpriority
68 #include <sys/time.h>
69 #include <fcntl.h>
70 #include <signal.h>
71 #include <sched.h>
72 #include <sys/un.h>
73 #include <sys/wait.h>
74 #include <ctype.h>
75 #include <sys/resource.h>
76 #include <grp.h>
77 #include <pwd.h>
78 #include <sys/stat.h>
79 #if defined(HAVE_SYSINFO)
80 #include <sys/sysinfo.h>
81 #endif
82 #ifdef linux
83 #include <sys/prctl.h>
84 #ifdef HAVE_CAP
85 #include <sys/capability.h>
86 #endif /* HAVE_CAP */
87 #endif /* linux */
88 #include <regex.h>
89
90 #if defined(SOLARIS)
91 int daemon(int, int);  /* defined in libresolv of all places */
92 #include <sys/loadavg.h>
93 #endif
94
95 #include "asterisk/paths.h"     /* we define here the variables so better agree on the prototype */
96 #include "asterisk/network.h"
97 #include "asterisk/cli.h"
98 #include "asterisk/channel.h"
99 #include "asterisk/features.h"
100 #include "asterisk/ulaw.h"
101 #include "asterisk/alaw.h"
102 #include "asterisk/callerid.h"
103 #include "asterisk/image.h"
104 #include "asterisk/tdd.h"
105 #include "asterisk/term.h"
106 #include "asterisk/manager.h"
107 #include "asterisk/cdr.h"
108 #include "asterisk/pbx.h"
109 #include "asterisk/enum.h"
110 #include "asterisk/rtp.h"
111 #include "asterisk/http.h"
112 #include "asterisk/udptl.h"
113 #include "asterisk/app.h"
114 #include "asterisk/lock.h"
115 #include "asterisk/utils.h"
116 #include "asterisk/file.h"
117 #include "asterisk/io.h"
118 #include "editline/histedit.h"
119 #include "asterisk/config.h"
120 #include "asterisk/ast_version.h"
121 #include "asterisk/linkedlists.h"
122 #include "asterisk/devicestate.h"
123 #include "asterisk/module.h"
124 #include "asterisk/dsp.h"
125 #include "asterisk/zapata.h"
126
127 #include "asterisk/doxyref.h"           /* Doxygen documentation */
128
129 #include "../defaults.h"
130
131 #ifndef AF_LOCAL
132 #define AF_LOCAL AF_UNIX
133 #define PF_LOCAL PF_UNIX
134 #endif
135
136 #define AST_MAX_CONNECTS 128
137 #define NUM_MSGS 64
138
139 /*! \brief Welcome message when starting a CLI interface */
140 #define WELCOME_MESSAGE \
141     ast_verbose("Asterisk %s, Copyright (C) 1999 - 2008 Digium, Inc. and others.\n" \
142                 "Created by Mark Spencer <markster@digium.com>\n" \
143                 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
144                 "This is free software, with components licensed under the GNU General Public\n" \
145                 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
146                 "certain conditions. Type 'core show license' for details.\n" \
147                 "=========================================================================\n", ast_get_version()) \
148
149 /*! \defgroup main_options Main Configuration Options
150  * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
151  * \arg \ref Config_ast "asterisk.conf"
152  * \note Some of them can be changed in the CLI 
153  */
154 /*! @{ */
155
156 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
157
158 int option_verbose;                             /*!< Verbosity level */
159 int option_debug;                               /*!< Debug level */
160 double option_maxload;                          /*!< Max load avg on system */
161 int option_maxcalls;                            /*!< Max number of active calls */
162 int option_maxfiles;                            /*!< Max number of open file handles (files, sockets) */
163 #if defined(HAVE_SYSINFO)
164 long option_minmemfree;                         /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
165 #endif
166
167 /*! @} */
168
169 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
170 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
171
172 static int ast_socket = -1;             /*!< UNIX Socket for allowing remote control */
173 static int ast_consock = -1;            /*!< UNIX Socket for controlling another asterisk */
174 pid_t ast_mainpid;
175 struct console {
176         int fd;                         /*!< File descriptor */
177         int p[2];                       /*!< Pipe */
178         pthread_t t;                    /*!< Thread of handler */
179         int mute;                       /*!< Is the console muted for logs */
180 };
181
182 struct ast_atexit {
183         void (*func)(void);
184         AST_RWLIST_ENTRY(ast_atexit) list;
185 };
186
187 static AST_RWLIST_HEAD_STATIC(atexits, ast_atexit);
188
189 struct timeval ast_startuptime;
190 struct timeval ast_lastreloadtime;
191
192 static History *el_hist;
193 static EditLine *el;
194 static char *remotehostname;
195
196 struct console consoles[AST_MAX_CONNECTS];
197
198 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
199
200 static int ast_el_add_history(char *);
201 static int ast_el_read_history(char *);
202 static int ast_el_write_history(char *);
203
204 struct _cfg_paths {
205         char config_dir[PATH_MAX];
206         char module_dir[PATH_MAX];
207         char spool_dir[PATH_MAX];
208         char monitor_dir[PATH_MAX];
209         char var_dir[PATH_MAX];
210         char data_dir[PATH_MAX];
211         char log_dir[PATH_MAX];
212         char agi_dir[PATH_MAX];
213         char run_dir[PATH_MAX];
214         char key_dir[PATH_MAX];
215
216         char config_file[PATH_MAX];
217         char db_path[PATH_MAX];
218         char pid_path[PATH_MAX];
219         char socket_path[PATH_MAX];
220         char run_user[PATH_MAX];
221         char run_group[PATH_MAX];
222         char system_name[128];
223 };
224
225 static struct _cfg_paths cfg_paths;
226
227 const char *ast_config_AST_CONFIG_DIR   = cfg_paths.config_dir;
228 const char *ast_config_AST_CONFIG_FILE  = cfg_paths.config_file;
229 const char *ast_config_AST_MODULE_DIR   = cfg_paths.module_dir;
230 const char *ast_config_AST_SPOOL_DIR    = cfg_paths.spool_dir;
231 const char *ast_config_AST_MONITOR_DIR  = cfg_paths.monitor_dir;
232 const char *ast_config_AST_VAR_DIR      = cfg_paths.var_dir;
233 const char *ast_config_AST_DATA_DIR     = cfg_paths.data_dir;
234 const char *ast_config_AST_LOG_DIR      = cfg_paths.log_dir;
235 const char *ast_config_AST_AGI_DIR      = cfg_paths.agi_dir;
236 const char *ast_config_AST_KEY_DIR      = cfg_paths.key_dir;
237 const char *ast_config_AST_RUN_DIR      = cfg_paths.run_dir;
238
239 const char *ast_config_AST_DB           = cfg_paths.db_path;
240 const char *ast_config_AST_PID          = cfg_paths.pid_path;
241 const char *ast_config_AST_SOCKET       = cfg_paths.socket_path;
242 const char *ast_config_AST_RUN_USER     = cfg_paths.run_user;
243 const char *ast_config_AST_RUN_GROUP    = cfg_paths.run_group;
244 const char *ast_config_AST_SYSTEM_NAME  = cfg_paths.system_name;
245
246 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
247 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
248 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
249 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
250
251 extern const char *ast_build_hostname;
252 extern const char *ast_build_kernel;
253 extern const char *ast_build_machine;
254 extern const char *ast_build_os;
255 extern const char *ast_build_date;
256 extern const char *ast_build_user;
257
258 static char *_argv[256];
259 static int shuttingdown;
260 static int restartnow;
261 static pthread_t consolethread = AST_PTHREADT_NULL;
262 static int canary_pid = 0;
263 static char canary_filename[128];
264
265 static char randompool[256];
266
267 static int sig_alert_pipe[2] = { -1, -1 };
268 static struct {
269          unsigned int need_reload:1;
270          unsigned int need_quit:1;
271 } sig_flags;
272
273 #if !defined(LOW_MEMORY)
274 struct file_version {
275         AST_RWLIST_ENTRY(file_version) list;
276         const char *file;
277         char *version;
278 };
279
280 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
281
282 void ast_register_file_version(const char *file, const char *version)
283 {
284         struct file_version *new;
285         char *work;
286         size_t version_length;
287
288         work = ast_strdupa(version);
289         work = ast_strip(ast_strip_quoted(work, "$", "$"));
290         version_length = strlen(work) + 1;
291         
292         if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
293                 return;
294
295         new->file = file;
296         new->version = (char *) new + sizeof(*new);
297         memcpy(new->version, work, version_length);
298         AST_RWLIST_WRLOCK(&file_versions);
299         AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
300         AST_RWLIST_UNLOCK(&file_versions);
301 }
302
303 void ast_unregister_file_version(const char *file)
304 {
305         struct file_version *find;
306
307         AST_RWLIST_WRLOCK(&file_versions);
308         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
309                 if (!strcasecmp(find->file, file)) {
310                         AST_RWLIST_REMOVE_CURRENT(list);
311                         break;
312                 }
313         }
314         AST_RWLIST_TRAVERSE_SAFE_END;
315         AST_RWLIST_UNLOCK(&file_versions);
316
317         if (find)
318                 ast_free(find);
319 }
320
321 /*! \brief Find version for given module name */
322 const char *ast_file_version_find(const char *file)
323 {
324         struct file_version *iterator;
325
326         AST_RWLIST_WRLOCK(&file_versions);
327         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, iterator, list) {
328                 if (!strcasecmp(iterator->file, file))
329                         break;
330         }
331         AST_RWLIST_TRAVERSE_SAFE_END;
332         AST_RWLIST_UNLOCK(&file_versions);
333         if (iterator)
334                 return iterator->version;
335         return NULL;
336 }      
337        
338
339
340 struct thread_list_t {
341         AST_RWLIST_ENTRY(thread_list_t) list;
342         char *name;
343         pthread_t id;
344 };
345
346 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
347
348 void ast_register_thread(char *name)
349
350         struct thread_list_t *new = ast_calloc(1, sizeof(*new));
351
352         if (!new)
353                 return;
354         new->id = pthread_self();
355         new->name = name; /* steal the allocated memory for the thread name */
356         AST_RWLIST_WRLOCK(&thread_list);
357         AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
358         AST_RWLIST_UNLOCK(&thread_list);
359 }
360
361 void ast_unregister_thread(void *id)
362 {
363         struct thread_list_t *x;
364
365         AST_RWLIST_WRLOCK(&thread_list);
366         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
367                 if ((void *) x->id == id) {
368                         AST_RWLIST_REMOVE_CURRENT(list);
369                         break;
370                 }
371         }
372         AST_RWLIST_TRAVERSE_SAFE_END;
373         AST_RWLIST_UNLOCK(&thread_list);
374         if (x) {
375                 ast_free(x->name);
376                 ast_free(x);
377         }
378 }
379
380 /*! \brief Give an overview of core settings */
381 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
382 {
383         char buf[BUFSIZ];
384         struct ast_tm tm;
385
386         switch (cmd) {
387         case CLI_INIT:
388                 e->command = "core show settings";
389                 e->usage = "Usage: core show settings\n"
390                            "       Show core misc settings";
391                 return NULL;
392         case CLI_GENERATE:
393                 return NULL;
394         }
395
396         ast_cli(a->fd, "\nPBX Core settings\n");
397         ast_cli(a->fd, "-----------------\n");
398         ast_cli(a->fd, "  Version:                     %s\n", ast_get_version());
399         if (option_maxcalls)
400                 ast_cli(a->fd, "  Maximum calls:               %d (Current %d)\n", option_maxcalls, ast_active_channels());
401         else
402                 ast_cli(a->fd, "  Maximum calls:               Not set\n");
403         if (option_maxfiles)
404                 ast_cli(a->fd, "  Maximum open file handles:   %d\n", option_maxfiles); 
405         else
406                 ast_cli(a->fd, "  Maximum open file handles:   Not set\n");
407         ast_cli(a->fd, "  Verbosity:                   %d\n", option_verbose);
408         ast_cli(a->fd, "  Debug level:                 %d\n", option_debug);
409         ast_cli(a->fd, "  Maximum load average:        %lf\n", option_maxload);
410 #if defined(HAVE_SYSINFO)
411         ast_cli(a->fd, "  Minimum free memory:         %ld MB\n", option_minmemfree);
412 #endif
413         if (ast_localtime(&ast_startuptime, &tm, NULL)) {
414                 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
415                 ast_cli(a->fd, "  Startup time:                %s\n", buf);
416         }
417         if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
418                 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
419                 ast_cli(a->fd, "  Last reload time:            %s\n", buf);
420         }
421         ast_cli(a->fd, "  System:                      %s/%s built by %s on %s %s\n", ast_build_os, ast_build_kernel, ast_build_user, ast_build_machine, ast_build_date);
422         ast_cli(a->fd, "  System name:                 %s\n", ast_config_AST_SYSTEM_NAME);
423         ast_cli(a->fd, "  Default language:            %s\n", defaultlanguage);
424         ast_cli(a->fd, "  Language prefix:             %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
425         ast_cli(a->fd, "  User name and group:         %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
426         ast_cli(a->fd, "  Executable includes:         %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
427         ast_cli(a->fd, "  Transcode via SLIN:          %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
428         ast_cli(a->fd, "  Internal timing:             %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
429         ast_cli(a->fd, "  Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
430
431         ast_cli(a->fd, "\n* Subsystems\n");
432         ast_cli(a->fd, "  -------------\n");
433         ast_cli(a->fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
434         ast_cli(a->fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
435         ast_cli(a->fd, "  Call data records:           %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
436         ast_cli(a->fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
437
438         /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */
439
440         ast_cli(a->fd, "\n* Directories\n");
441         ast_cli(a->fd, "  -------------\n");
442         ast_cli(a->fd, "  Configuration file:          %s\n", ast_config_AST_CONFIG_FILE);
443         ast_cli(a->fd, "  Configuration directory:     %s\n", ast_config_AST_CONFIG_DIR);
444         ast_cli(a->fd, "  Module directory:            %s\n", ast_config_AST_MODULE_DIR);
445         ast_cli(a->fd, "  Spool directory:             %s\n", ast_config_AST_SPOOL_DIR);
446         ast_cli(a->fd, "  Log directory:               %s\n", ast_config_AST_LOG_DIR);
447         ast_cli(a->fd, "\n\n");
448         return CLI_SUCCESS;
449 }
450
451 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
452 {
453         int count = 0;
454         struct thread_list_t *cur;
455         switch (cmd) {
456         case CLI_INIT:
457                 e->command = "core show threads";
458                 e->usage = 
459                         "Usage: core show threads\n"
460                         "       List threads currently active in the system.\n";
461                 return NULL;
462         case CLI_GENERATE:
463                 return NULL;
464         }
465
466         AST_RWLIST_RDLOCK(&thread_list);
467         AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
468                 ast_cli(a->fd, "%p %s\n", (void *)cur->id, cur->name);
469                 count++;
470         }
471         AST_RWLIST_UNLOCK(&thread_list);
472         ast_cli(a->fd, "%d threads listed.\n", count);
473         return CLI_SUCCESS;
474 }
475
476 #if defined(HAVE_SYSINFO)
477 /*! \brief Give an overview of system statistics */
478 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
479 {
480         struct sysinfo sys_info;
481         switch (cmd) {
482         case CLI_INIT:
483                 e->command = "core show sysinfo";
484                 e->usage =
485                         "Usage: core show sysinfo\n"
486                         "       List current system information.\n";
487                 return NULL;
488         case CLI_GENERATE:
489                 return NULL;
490         }
491         if (sysinfo(&sys_info)) {
492                 ast_cli(a->fd, "FAILED to retrieve system information\n\n");
493                 return CLI_FAILURE;
494         }
495         ast_cli(a->fd, "\nSystem Statistics\n");
496         ast_cli(a->fd, "-----------------\n");
497         ast_cli(a->fd, "  System Uptime:             %ld hours\n", sys_info.uptime/3600);
498         ast_cli(a->fd, "  Total RAM:                 %ld KiB\n", (sys_info.totalram / sys_info.mem_unit)/1024);
499         ast_cli(a->fd, "  Free RAM:                  %ld KiB\n", (sys_info.freeram / sys_info.mem_unit)/1024);
500         ast_cli(a->fd, "  Buffer RAM:                %ld KiB\n", (sys_info.bufferram / sys_info.mem_unit)/1024);
501         ast_cli(a->fd, "  Total Swap Space:          %ld KiB\n", (sys_info.totalswap / sys_info.mem_unit)/1024);
502         ast_cli(a->fd, "  Free Swap Space:           %ld KiB\n\n", (sys_info.freeswap / sys_info.mem_unit)/1024);
503         ast_cli(a->fd, "  Number of Processes:       %d \n\n", sys_info.procs);
504         return CLI_SUCCESS;
505 }
506 #endif
507
508 struct profile_entry {
509         const char *name;
510         uint64_t        scale;  /* if non-zero, values are scaled by this */
511         int64_t mark;
512         int64_t value;
513         int64_t events;
514 };
515
516 struct profile_data {
517         int entries;
518         int max_size;
519         struct profile_entry e[0];
520 };
521
522 static struct profile_data *prof_data;
523
524 /*! \brief allocates a counter with a given name and scale.
525  * \return Returns the identifier of the counter.
526  */
527 int ast_add_profile(const char *name, uint64_t scale)
528 {
529         int l = sizeof(struct profile_data);
530         int n = 10;     /* default entries */
531
532         if (prof_data == NULL) {
533                 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
534                 if (prof_data == NULL)
535                         return -1;
536                 prof_data->entries = 0;
537                 prof_data->max_size = n;
538         }
539         if (prof_data->entries >= prof_data->max_size) {
540                 void *p;
541                 n = prof_data->max_size + 20;
542                 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
543                 if (p == NULL)
544                         return -1;
545                 prof_data = p;
546                 prof_data->max_size = n;
547         }
548         n = prof_data->entries++;
549         prof_data->e[n].name = ast_strdup(name);
550         prof_data->e[n].value = 0;
551         prof_data->e[n].events = 0;
552         prof_data->e[n].mark = 0;
553         prof_data->e[n].scale = scale;
554         return n;
555 }
556
557 int64_t ast_profile(int i, int64_t delta)
558 {
559         if (!prof_data || i < 0 || i > prof_data->entries)      /* invalid index */
560                 return 0;
561         if (prof_data->e[i].scale > 1)
562                 delta /= prof_data->e[i].scale;
563         prof_data->e[i].value += delta;
564         prof_data->e[i].events++;
565         return prof_data->e[i].value;
566 }
567
568 #if defined ( __i386__) && (defined(__FreeBSD__) || defined(linux))
569 #if defined(__FreeBSD__)
570 #include <machine/cpufunc.h>
571 #elif defined(linux)
572 static __inline uint64_t
573 rdtsc(void)
574
575         uint64_t rv;
576
577         __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
578         return (rv);
579 }
580 #endif
581 #else   /* supply a dummy function on other platforms */
582 static __inline uint64_t
583 rdtsc(void)
584 {
585         return 0;
586 }
587 #endif
588
589 int64_t ast_mark(int i, int startstop)
590 {
591         if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
592                 return 0;
593         if (startstop == 1)
594                 prof_data->e[i].mark = rdtsc();
595         else {
596                 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
597                 if (prof_data->e[i].scale > 1)
598                         prof_data->e[i].mark /= prof_data->e[i].scale;
599                 prof_data->e[i].value += prof_data->e[i].mark;
600                 prof_data->e[i].events++;
601         }
602         return prof_data->e[i].mark;
603 }
604
605 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
606         max = prof_data->entries;\
607         if  (a->argc > 3) { /* specific entries */ \
608                 if (isdigit(a->argv[3][0])) { \
609                         min = atoi(a->argv[3]); \
610                         if (a->argc == 5 && strcmp(a->argv[4], "-")) \
611                                 max = atoi(a->argv[4]); \
612                 } else \
613                         search = a->argv[3]; \
614         } \
615         if (max > prof_data->entries) \
616                 max = prof_data->entries;
617
618 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
619 {
620         int i, min, max;
621         char *search = NULL;
622         switch (cmd) {
623         case CLI_INIT:
624                 e->command = "core show profile";
625                 e->usage = "Usage: core show profile\n"
626                            "       show profile information";
627                 return NULL;
628         case CLI_GENERATE:
629                 return NULL;
630         }
631
632         if (prof_data == NULL)
633                 return 0;
634
635         DEFINE_PROFILE_MIN_MAX_VALUES;
636         ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
637                 prof_data->entries, prof_data->max_size);
638         ast_cli(a->fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
639                         "Value", "Average", "Name");
640         for (i = min; i < max; i++) {
641                 struct profile_entry *e = &prof_data->e[i];
642                 if (!search || strstr(prof_data->e[i].name, search))
643                     ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
644                         i,
645                         (long)e->scale,
646                         (long)e->events, (long long)e->value,
647                         (long long)(e->events ? e->value / e->events : e->value),
648                         e->name);
649         }
650         return CLI_SUCCESS;
651 }
652
653 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
654 {
655         int i, min, max;
656         char *search = NULL;
657         switch (cmd) {
658         case CLI_INIT:
659                 e->command = "core clear profile";
660                 e->usage = "Usage: core clear profile\n"
661                            "       clear profile information";
662                 return NULL;
663         case CLI_GENERATE:
664                 return NULL;
665         }
666
667         if (prof_data == NULL)
668                 return 0;
669
670         DEFINE_PROFILE_MIN_MAX_VALUES;
671         for (i= min; i < max; i++) {
672                 if (!search || strstr(prof_data->e[i].name, search)) {
673                         prof_data->e[i].value = 0;
674                         prof_data->e[i].events = 0;
675                 }
676         }
677         return CLI_SUCCESS;
678 }
679 #undef DEFINE_PROFILE_MIN_MAX_VALUES
680
681 /*! \brief CLI command to list module versions */
682 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
683 {
684 #define FORMAT "%-25.25s %-40.40s\n"
685         struct file_version *iterator;
686         regex_t regexbuf;
687         int havepattern = 0;
688         int havename = 0;
689         int count_files = 0;
690         char *ret = NULL;
691         int matchlen, which = 0;
692         struct file_version *find;
693
694         switch (cmd) {
695         case CLI_INIT:
696                 e->command = "core show file version [like]";
697                 e->usage = 
698                         "Usage: core show file version [like <pattern>]\n"
699                         "       Lists the revision numbers of the files used to build this copy of Asterisk.\n"
700                         "       Optional regular expression pattern is used to filter the file list.\n";
701                 return NULL;
702         case CLI_GENERATE:
703                 matchlen = strlen(a->word);
704                 if (a->pos != 3)
705                         return NULL;
706                 AST_RWLIST_RDLOCK(&file_versions);
707                 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
708                         if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
709                                 ret = ast_strdup(find->file);
710                                 break;
711                         }
712                 }
713                 AST_RWLIST_UNLOCK(&file_versions);
714                 return ret;
715         }
716
717
718         switch (a->argc) {
719         case 6:
720                 if (!strcasecmp(a->argv[4], "like")) {
721                         if (regcomp(&regexbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
722                                 return CLI_SHOWUSAGE;
723                         havepattern = 1;
724                 } else
725                         return CLI_SHOWUSAGE;
726                 break;
727         case 5:
728                 havename = 1;
729                 break;
730         case 4:
731                 break;
732         default:
733                 return CLI_SHOWUSAGE;
734         }
735
736         ast_cli(a->fd, FORMAT, "File", "Revision");
737         ast_cli(a->fd, FORMAT, "----", "--------");
738         AST_RWLIST_RDLOCK(&file_versions);
739         AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
740                 if (havename && strcasecmp(iterator->file, a->argv[4]))
741                         continue;
742
743                 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
744                         continue;
745
746                 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
747                 count_files++;
748                 if (havename)
749                         break;
750         }
751         AST_RWLIST_UNLOCK(&file_versions);
752         if (!havename) {
753                 ast_cli(a->fd, "%d files listed.\n", count_files);
754         }
755
756         if (havepattern)
757                 regfree(&regexbuf);
758
759         return CLI_SUCCESS;
760 #undef FORMAT
761 }
762
763 #endif /* ! LOW_MEMORY */
764
765 int ast_register_atexit(void (*func)(void))
766 {
767         struct ast_atexit *ae;
768
769         if (!(ae = ast_calloc(1, sizeof(*ae))))
770                 return -1;
771
772         ae->func = func;
773
774         ast_unregister_atexit(func);    
775
776         AST_RWLIST_WRLOCK(&atexits);
777         AST_RWLIST_INSERT_HEAD(&atexits, ae, list);
778         AST_RWLIST_UNLOCK(&atexits);
779
780         return 0;
781 }
782
783 void ast_unregister_atexit(void (*func)(void))
784 {
785         struct ast_atexit *ae = NULL;
786
787         AST_RWLIST_WRLOCK(&atexits);
788         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
789                 if (ae->func == func) {
790                         AST_RWLIST_REMOVE_CURRENT(list);
791                         break;
792                 }
793         }
794         AST_RWLIST_TRAVERSE_SAFE_END;
795         AST_RWLIST_UNLOCK(&atexits);
796
797         if (ae)
798                 free(ae);
799 }
800
801 static int fdprint(int fd, const char *s)
802 {
803         return write(fd, s, strlen(s) + 1);
804 }
805
806 /*! \brief NULL handler so we can collect the child exit status */
807 static void null_sig_handler(int signal)
808 {
809
810 }
811
812 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
813 /*! \brief Keep track of how many threads are currently trying to wait*() on
814  *  a child process */
815 static unsigned int safe_system_level = 0;
816 static void *safe_system_prev_handler;
817
818 void ast_replace_sigchld(void)
819 {
820         unsigned int level;
821
822         ast_mutex_lock(&safe_system_lock);
823         level = safe_system_level++;
824
825         /* only replace the handler if it has not already been done */
826         if (level == 0)
827                 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
828
829         ast_mutex_unlock(&safe_system_lock);
830 }
831
832 void ast_unreplace_sigchld(void)
833 {
834         unsigned int level;
835
836         ast_mutex_lock(&safe_system_lock);
837         level = --safe_system_level;
838
839         /* only restore the handler if we are the last one */
840         if (level == 0)
841                 signal(SIGCHLD, safe_system_prev_handler);
842
843         ast_mutex_unlock(&safe_system_lock);
844 }
845
846 int ast_safe_system(const char *s)
847 {
848         pid_t pid;
849 #ifdef HAVE_WORKING_FORK
850         int x;
851 #endif
852         int res;
853         struct rusage rusage;
854         int status;
855
856 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
857         ast_replace_sigchld();
858
859 #ifdef HAVE_WORKING_FORK
860         pid = fork();
861 #else
862         pid = vfork();
863 #endif  
864
865         if (pid == 0) {
866 #ifdef HAVE_WORKING_FORK
867                 if (ast_opt_high_priority)
868                         ast_set_priority(0);
869                 /* Close file descriptors and launch system command */
870                 for (x = STDERR_FILENO + 1; x < 4096; x++)
871                         close(x);
872 #endif
873                 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
874                 _exit(1);
875         } else if (pid > 0) {
876                 for (;;) {
877                         res = wait4(pid, &status, 0, &rusage);
878                         if (res > -1) {
879                                 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
880                                 break;
881                         } else if (errno != EINTR) 
882                                 break;
883                 }
884         } else {
885                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
886                 res = -1;
887         }
888
889         ast_unreplace_sigchld();
890 #else
891         res = -1;
892 #endif
893
894         return res;
895 }
896
897 /*!
898  * \brief mute or unmute a console from logging
899  */
900 void ast_console_toggle_mute(int fd, int silent) {
901         int x;
902         for (x = 0;x < AST_MAX_CONNECTS; x++) {
903                 if (fd == consoles[x].fd) {
904                         if (consoles[x].mute) {
905                                 consoles[x].mute = 0;
906                                 if (!silent)
907                                         ast_cli(fd, "Console is not muted anymore.\n");
908                         } else {
909                                 consoles[x].mute = 1;
910                                 if (!silent)
911                                         ast_cli(fd, "Console is muted.\n");
912                         }
913                         return;
914                 }
915         }
916         ast_cli(fd, "Couldn't find remote console.\n");
917 }
918
919 /*!
920  * \brief log the string to all attached console clients
921  */
922 static void ast_network_puts_mutable(const char *string)
923 {
924         int x;
925         for (x = 0;x < AST_MAX_CONNECTS; x++) {
926                 if (consoles[x].mute)
927                         continue;
928                 if (consoles[x].fd > -1) 
929                         fdprint(consoles[x].p[1], string);
930         }
931 }
932
933 /*!
934  * \brief log the string to the console, and all attached
935  * console clients
936  */
937 void ast_console_puts_mutable(const char *string)
938 {
939         fputs(string, stdout);
940         fflush(stdout);
941         ast_network_puts_mutable(string);
942 }
943
944 /*!
945  * \brief write the string to all attached console clients
946  */
947 static void ast_network_puts(const char *string)
948 {
949         int x;
950         for (x = 0; x < AST_MAX_CONNECTS; x++) {
951                 if (consoles[x].fd > -1) 
952                         fdprint(consoles[x].p[1], string);
953         }
954 }
955
956 /*!
957  * write the string to the console, and all attached
958  * console clients
959  */
960 void ast_console_puts(const char *string)
961 {
962         fputs(string, stdout);
963         fflush(stdout);
964         ast_network_puts(string);
965 }
966
967 static void network_verboser(const char *s)
968 {
969         ast_network_puts_mutable(s);
970 }
971
972 static pthread_t lthread;
973
974 static void *netconsole(void *vconsole)
975 {
976         struct console *con = vconsole;
977         char hostname[MAXHOSTNAMELEN] = "";
978         char tmp[512];
979         int res;
980         struct pollfd fds[2];
981         
982         if (gethostname(hostname, sizeof(hostname)-1))
983                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
984         snprintf(tmp, sizeof(tmp), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
985         fdprint(con->fd, tmp);
986         for (;;) {
987                 fds[0].fd = con->fd;
988                 fds[0].events = POLLIN;
989                 fds[0].revents = 0;
990                 fds[1].fd = con->p[0];
991                 fds[1].events = POLLIN;
992                 fds[1].revents = 0;
993
994                 res = poll(fds, 2, -1);
995                 if (res < 0) {
996                         if (errno != EINTR)
997                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
998                         continue;
999                 }
1000                 if (fds[0].revents) {
1001                         res = read(con->fd, tmp, sizeof(tmp));
1002                         if (res < 1) {
1003                                 break;
1004                         }
1005                         tmp[res] = 0;
1006                         ast_cli_command_multiple(con->fd, res, tmp);
1007                 }
1008                 if (fds[1].revents) {
1009                         res = read(con->p[0], tmp, sizeof(tmp));
1010                         if (res < 1) {
1011                                 ast_log(LOG_ERROR, "read returned %d\n", res);
1012                                 break;
1013                         }
1014                         res = write(con->fd, tmp, res);
1015                         if (res < 1)
1016                                 break;
1017                 }
1018         }
1019         ast_verb(3, "Remote UNIX connection disconnected\n");
1020         close(con->fd);
1021         close(con->p[0]);
1022         close(con->p[1]);
1023         con->fd = -1;
1024         
1025         return NULL;
1026 }
1027
1028 static void *listener(void *unused)
1029 {
1030         struct sockaddr_un sunaddr;
1031         int s;
1032         socklen_t len;
1033         int x;
1034         int flags;
1035         struct pollfd fds[1];
1036         for (;;) {
1037                 if (ast_socket < 0)
1038                         return NULL;
1039                 fds[0].fd = ast_socket;
1040                 fds[0].events = POLLIN;
1041                 s = poll(fds, 1, -1);
1042                 pthread_testcancel();
1043                 if (s < 0) {
1044                         if (errno != EINTR)
1045                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1046                         continue;
1047                 }
1048                 len = sizeof(sunaddr);
1049                 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1050                 if (s < 0) {
1051                         if (errno != EINTR)
1052                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1053                 } else {
1054                         for (x = 0; x < AST_MAX_CONNECTS; x++) {
1055                                 if (consoles[x].fd < 0) {
1056                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1057                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1058                                                 consoles[x].fd = -1;
1059                                                 fdprint(s, "Server failed to create pipe\n");
1060                                                 close(s);
1061                                                 break;
1062                                         }
1063                                         flags = fcntl(consoles[x].p[1], F_GETFL);
1064                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1065                                         consoles[x].fd = s;
1066                                         consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1067                                         if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1068                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1069                                                 close(consoles[x].p[0]);
1070                                                 close(consoles[x].p[1]);
1071                                                 consoles[x].fd = -1;
1072                                                 fdprint(s, "Server failed to spawn thread\n");
1073                                                 close(s);
1074                                         }
1075                                         break;
1076                                 }
1077                         }
1078                         if (x >= AST_MAX_CONNECTS) {
1079                                 fdprint(s, "No more connections allowed\n");
1080                                 ast_log(LOG_WARNING, "No more connections allowed\n");
1081                                 close(s);
1082                         } else if (consoles[x].fd > -1) 
1083                                 ast_verb(3, "Remote UNIX connection\n");
1084                 }
1085         }
1086         return NULL;
1087 }
1088
1089 static int ast_makesocket(void)
1090 {
1091         struct sockaddr_un sunaddr;
1092         int res;
1093         int x;
1094         uid_t uid = -1;
1095         gid_t gid = -1;
1096
1097         for (x = 0; x < AST_MAX_CONNECTS; x++)  
1098                 consoles[x].fd = -1;
1099         unlink(ast_config_AST_SOCKET);
1100         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1101         if (ast_socket < 0) {
1102                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1103                 return -1;
1104         }               
1105         memset(&sunaddr, 0, sizeof(sunaddr));
1106         sunaddr.sun_family = AF_LOCAL;
1107         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1108         res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1109         if (res) {
1110                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1111                 close(ast_socket);
1112                 ast_socket = -1;
1113                 return -1;
1114         }
1115         res = listen(ast_socket, 2);
1116         if (res < 0) {
1117                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1118                 close(ast_socket);
1119                 ast_socket = -1;
1120                 return -1;
1121         }
1122         ast_register_verbose(network_verboser);
1123         ast_pthread_create_background(&lthread, NULL, listener, NULL);
1124
1125         if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1126                 struct passwd *pw;
1127                 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1128                         ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1129                 else
1130                         uid = pw->pw_uid;
1131         }
1132                 
1133         if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1134                 struct group *grp;
1135                 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1136                         ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1137                 else
1138                         gid = grp->gr_gid;
1139         }
1140
1141         if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1142                 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1143
1144         if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1145                 int p1;
1146                 mode_t p;
1147                 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
1148                 p = p1;
1149                 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1150                         ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1151         }
1152
1153         return 0;
1154 }
1155
1156 static int ast_tryconnect(void)
1157 {
1158         struct sockaddr_un sunaddr;
1159         int res;
1160         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1161         if (ast_consock < 0) {
1162                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
1163                 return 0;
1164         }
1165         memset(&sunaddr, 0, sizeof(sunaddr));
1166         sunaddr.sun_family = AF_LOCAL;
1167         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1168         res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1169         if (res) {
1170                 close(ast_consock);
1171                 ast_consock = -1;
1172                 return 0;
1173         } else
1174                 return 1;
1175 }
1176
1177 /*! \brief Urgent handler
1178
1179  Called by soft_hangup to interrupt the poll, read, or other
1180  system call.  We don't actually need to do anything though.  
1181  Remember: Cannot EVER ast_log from within a signal handler 
1182  */
1183 static void urg_handler(int num)
1184 {
1185         signal(num, urg_handler);
1186         return;
1187 }
1188
1189 static void hup_handler(int num)
1190 {
1191         int a = 0;
1192         if (option_verbose > 1) 
1193                 printf("Received HUP signal -- Reloading configs\n");
1194         if (restartnow)
1195                 execvp(_argv[0], _argv);
1196         sig_flags.need_reload = 1;
1197         if (sig_alert_pipe[1] != -1)
1198                 write(sig_alert_pipe[1], &a, sizeof(a));
1199         signal(num, hup_handler);
1200 }
1201
1202 static void child_handler(int sig)
1203 {
1204         /* Must not ever ast_log or ast_verbose within signal handler */
1205         int n, status;
1206
1207         /*
1208          * Reap all dead children -- not just one
1209          */
1210         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1211                 ;
1212         if (n == 0 && option_debug)     
1213                 printf("Huh?  Child handler, but nobody there?\n");
1214         signal(sig, child_handler);
1215 }
1216
1217 /*! \brief Set maximum open files */
1218 static void set_ulimit(int value)
1219 {
1220         struct rlimit l = {0, 0};
1221         
1222         if (value <= 0) {
1223                 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1224                 return;
1225         }
1226         
1227         l.rlim_cur = value;
1228         l.rlim_max = value;
1229         
1230         if (setrlimit(RLIMIT_NOFILE, &l)) {
1231                 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1232                 return;
1233         }
1234         
1235         ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1236         
1237         return;
1238 }
1239
1240 /*! \brief Set an X-term or screen title */
1241 static void set_title(char *text)
1242 {
1243         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1244                 fprintf(stdout, "\033]2;%s\007", text);
1245 }
1246
1247 static void set_icon(char *text)
1248 {
1249         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1250                 fprintf(stdout, "\033]1;%s\007", text);
1251 }
1252
1253 /*! \brief We set ourselves to a high priority, that we might pre-empt everything
1254    else.  If your PBX has heavy activity on it, this is a good thing.  */
1255 int ast_set_priority(int pri)
1256 {
1257         struct sched_param sched;
1258         memset(&sched, 0, sizeof(sched));
1259 #ifdef __linux__
1260         if (pri) {  
1261                 sched.sched_priority = 10;
1262                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1263                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1264                         return -1;
1265                 } else
1266                         if (option_verbose)
1267                                 ast_verbose("Set to realtime thread\n");
1268         } else {
1269                 sched.sched_priority = 0;
1270                 /* According to the manpage, these parameters can never fail. */
1271                 sched_setscheduler(0, SCHED_OTHER, &sched);
1272         }
1273 #else
1274         if (pri) {
1275                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1276                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1277                         return -1;
1278                 } else
1279                         if (option_verbose)
1280                                 ast_verbose("Set to high priority\n");
1281         } else {
1282                 /* According to the manpage, these parameters can never fail. */
1283                 setpriority(PRIO_PROCESS, 0, 0);
1284         }
1285 #endif
1286         return 0;
1287 }
1288
1289 static void ast_run_atexits(void)
1290 {
1291         struct ast_atexit *ae;
1292         AST_RWLIST_RDLOCK(&atexits);
1293         AST_RWLIST_TRAVERSE(&atexits, ae, list) {
1294                 if (ae->func) 
1295                         ae->func();
1296         }
1297         AST_RWLIST_UNLOCK(&atexits);
1298 }
1299
1300 static void quit_handler(int num, int nice, int safeshutdown, int restart)
1301 {
1302         char filename[80] = "";
1303         time_t s,e;
1304         int x;
1305         /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
1306         ast_cdr_engine_term();
1307         if (safeshutdown) {
1308                 shuttingdown = 1;
1309                 if (!nice) {
1310                         /* Begin shutdown routine, hanging up active channels */
1311                         ast_begin_shutdown(1);
1312                         if (option_verbose && ast_opt_console)
1313                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1314                         time(&s);
1315                         for (;;) {
1316                                 time(&e);
1317                                 /* Wait up to 15 seconds for all channels to go away */
1318                                 if ((e - s) > 15)
1319                                         break;
1320                                 if (!ast_active_channels())
1321                                         break;
1322                                 if (!shuttingdown)
1323                                         break;
1324                                 /* Sleep 1/10 of a second */
1325                                 usleep(100000);
1326                         }
1327                 } else {
1328                         if (nice < 2)
1329                                 ast_begin_shutdown(0);
1330                         if (option_verbose && ast_opt_console)
1331                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1332                         for (;;) {
1333                                 if (!ast_active_channels())
1334                                         break;
1335                                 if (!shuttingdown)
1336                                         break;
1337                                 sleep(1);
1338                         }
1339                 }
1340
1341                 if (!shuttingdown) {
1342                         if (option_verbose && ast_opt_console)
1343                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1344                         return;
1345                 }
1346
1347                 if (nice)
1348                         ast_module_shutdown();
1349         }
1350         if (ast_opt_console || ast_opt_remote) {
1351                 if (getenv("HOME")) 
1352                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1353                 if (!ast_strlen_zero(filename))
1354                         ast_el_write_history(filename);
1355                 if (el != NULL)
1356                         el_end(el);
1357                 if (el_hist != NULL)
1358                         history_end(el_hist);
1359         }
1360         if (option_verbose)
1361                 ast_verbose("Executing last minute cleanups\n");
1362         ast_run_atexits();
1363         /* Called on exit */
1364         if (option_verbose && ast_opt_console)
1365                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1366         ast_debug(1, "Asterisk ending (%d).\n", num);
1367         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1368         if (ast_socket > -1) {
1369                 pthread_cancel(lthread);
1370                 close(ast_socket);
1371                 ast_socket = -1;
1372                 unlink(ast_config_AST_SOCKET);
1373         }
1374         if (ast_consock > -1)
1375                 close(ast_consock);
1376         if (!ast_opt_remote)
1377                 unlink(ast_config_AST_PID);
1378         printf("%s", term_quit());
1379         if (restart) {
1380                 if (option_verbose || ast_opt_console)
1381                         ast_verbose("Preparing for Asterisk restart...\n");
1382                 /* Mark all FD's for closing on exec */
1383                 for (x=3; x < 32768; x++) {
1384                         fcntl(x, F_SETFD, FD_CLOEXEC);
1385                 }
1386                 if (option_verbose || ast_opt_console)
1387                         ast_verbose("Asterisk is now restarting...\n");
1388                 restartnow = 1;
1389
1390                 /* close logger */
1391                 close_logger();
1392
1393                 /* If there is a consolethread running send it a SIGHUP 
1394                    so it can execvp, otherwise we can do it ourselves */
1395                 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1396                         pthread_kill(consolethread, SIGHUP);
1397                         /* Give the signal handler some time to complete */
1398                         sleep(2);
1399                 } else
1400                         execvp(_argv[0], _argv);
1401         
1402         } else {
1403                 /* close logger */
1404                 close_logger();
1405         }
1406         exit(0);
1407 }
1408
1409 static void __quit_handler(int num)
1410 {
1411         int a = 0;
1412         sig_flags.need_quit = 1;
1413         if (sig_alert_pipe[1] != -1)
1414                 write(sig_alert_pipe[1], &a, sizeof(a));
1415         /* There is no need to restore the signal handler here, since the app
1416          * is going to exit */
1417 }
1418
1419 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1420 {
1421         const char *c;
1422         if (!strncmp(s, cmp, strlen(cmp))) {
1423                 c = s + strlen(cmp);
1424                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1425                 return c;
1426         }
1427         return NULL;
1428 }
1429
1430 static void console_verboser(const char *s)
1431 {
1432         char tmp[80];
1433         const char *c = NULL;
1434
1435         if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1436             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1437             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1438             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1439                 fputs(tmp, stdout);
1440                 fputs(c, stdout);
1441         } else
1442                 fputs(s, stdout);
1443
1444         fflush(stdout);
1445         
1446         /* Wake up a poll()ing console */
1447         if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
1448                 pthread_kill(consolethread, SIGURG);
1449 }
1450
1451 static int ast_all_zeros(char *s)
1452 {
1453         while (*s) {
1454                 if (*s > 32)
1455                         return 0;
1456                 s++;  
1457         }
1458         return 1;
1459 }
1460
1461 static void consolehandler(char *s)
1462 {
1463         printf("%s", term_end());
1464         fflush(stdout);
1465
1466         /* Called when readline data is available */
1467         if (!ast_all_zeros(s))
1468                 ast_el_add_history(s);
1469         /* The real handler for bang */
1470         if (s[0] == '!') {
1471                 if (s[1])
1472                         ast_safe_system(s+1);
1473                 else
1474                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1475         } else 
1476                 ast_cli_command(STDOUT_FILENO, s);
1477 }
1478
1479 static int remoteconsolehandler(char *s)
1480 {
1481         int ret = 0;
1482
1483         /* Called when readline data is available */
1484         if (!ast_all_zeros(s))
1485                 ast_el_add_history(s);
1486         /* The real handler for bang */
1487         if (s[0] == '!') {
1488                 if (s[1])
1489                         ast_safe_system(s+1);
1490                 else
1491                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1492                 ret = 1;
1493         }
1494         if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1495             (s[4] == '\0' || isspace(s[4]))) {
1496                 quit_handler(0, 0, 0, 0);
1497                 ret = 1;
1498         }
1499
1500         return ret;
1501 }
1502
1503 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1504 {
1505         switch (cmd) {
1506         case CLI_INIT:
1507                 e->command = "core show version";
1508                 e->usage = 
1509                         "Usage: core show version\n"
1510                         "       Shows Asterisk version information.\n";
1511                 return NULL;
1512         case CLI_GENERATE:
1513                 return NULL;
1514         }
1515
1516         if (a->argc != 3)
1517                 return CLI_SHOWUSAGE;
1518         ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
1519                 ast_get_version(), ast_build_user, ast_build_hostname,
1520                 ast_build_machine, ast_build_os, ast_build_date);
1521         return CLI_SUCCESS;
1522 }
1523
1524 #if 0
1525 static int handle_quit(int fd, int argc, char *argv[])
1526 {
1527         if (argc != 1)
1528                 return RESULT_SHOWUSAGE;
1529         quit_handler(0, 0, 1, 0);
1530         return RESULT_SUCCESS;
1531 }
1532 #endif
1533
1534 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1535 {
1536         switch (cmd) {
1537         case CLI_INIT:
1538                 e->command = "core stop now";
1539                 e->usage = 
1540                         "Usage: core stop now\n"
1541                         "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1542                 return NULL;
1543         case CLI_GENERATE:
1544                 return NULL;
1545         }
1546
1547         if (a->argc != e->args)
1548                 return CLI_SHOWUSAGE;
1549         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1550         return CLI_SUCCESS;
1551 }
1552
1553 static char *handle_stop_now_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1554 {
1555         char *res = handle_stop_now(e, cmd, a);
1556         if (cmd == CLI_INIT)
1557                 e->command = "stop now";
1558         return res;
1559 }
1560
1561 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1562 {
1563         switch (cmd) {
1564         case CLI_INIT:
1565                 e->command = "core stop gracefully";
1566                 e->usage = 
1567                         "Usage: core stop gracefully\n"
1568                         "       Causes Asterisk to not accept new calls, and exit when all\n"
1569                         "       active calls have terminated normally.\n";
1570                 return NULL;
1571         case CLI_GENERATE:
1572                 return NULL;
1573         }
1574
1575         if (a->argc != e->args)
1576                 return CLI_SHOWUSAGE;
1577         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1578         return CLI_SUCCESS;
1579 }
1580
1581 static char *handle_stop_gracefully_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1582 {
1583         char *res = handle_stop_gracefully(e, cmd, a);
1584         if (cmd == CLI_INIT)
1585                 e->command = "stop gracefully";
1586         return res;
1587 }
1588
1589 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1590 {
1591         switch (cmd) {
1592         case CLI_INIT:
1593                 e->command = "core stop when convenient";
1594                 e->usage = 
1595                         "Usage: core stop when convenient\n"
1596                         "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1597                 return NULL;
1598         case CLI_GENERATE:
1599                 return NULL;
1600         }
1601
1602         if (a->argc != e->args)
1603                 return CLI_SHOWUSAGE;
1604         ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
1605         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1606         return CLI_SUCCESS;
1607 }
1608
1609 static char *handle_stop_when_convenient_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1610 {
1611         char *res = handle_stop_when_convenient(e, cmd, a);
1612         if (cmd == CLI_INIT)
1613                 e->command = "stop when convenient";
1614         return res;
1615 }
1616
1617 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1618 {
1619         switch (cmd) {
1620         case CLI_INIT:
1621                 e->command = "core restart now";
1622                 e->usage = 
1623                         "Usage: core restart now\n"
1624                         "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1625                         "       restart.\n";
1626                 return NULL;
1627         case CLI_GENERATE:
1628                 return NULL;
1629         }
1630
1631         if (a->argc != e->args)
1632                 return CLI_SHOWUSAGE;
1633         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1634         return CLI_SUCCESS;
1635 }
1636
1637 static char *handle_restart_now_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1638 {
1639         char *res = handle_restart_now(e, cmd, a);
1640         if (cmd == CLI_INIT)
1641                 e->command = "restart now";
1642         return res;
1643 }
1644
1645 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1646 {
1647         switch (cmd) {
1648         case CLI_INIT:
1649                 e->command = "core restart gracefully";
1650                 e->usage = 
1651                         "Usage: core restart gracefully\n"
1652                         "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1653                         "       restart when all active calls have ended.\n";
1654                 return NULL;
1655         case CLI_GENERATE:
1656                 return NULL;
1657         }
1658
1659         if (a->argc != e->args)
1660                 return CLI_SHOWUSAGE;
1661         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1662         return CLI_SUCCESS;
1663 }
1664
1665 static char *handle_restart_gracefully_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1666 {
1667         char *res = handle_restart_gracefully(e, cmd, a);
1668         if (cmd == CLI_INIT)
1669                 e->command = "restart gracefully";
1670         return res;
1671 }
1672
1673 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1674 {
1675         switch (cmd) {
1676         case CLI_INIT:
1677                 e->command = "core restart when convenient";
1678                 e->usage = 
1679                         "Usage: core restart when convenient\n"
1680                         "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1681                 return NULL;
1682         case CLI_GENERATE:
1683                 return NULL;
1684         }
1685
1686         if (a->argc != e->args)
1687                 return CLI_SHOWUSAGE;
1688         ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
1689         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1690         return CLI_SUCCESS;
1691 }
1692
1693 static char *handle_restart_when_convenient_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1694 {
1695         char *res = handle_restart_when_convenient(e, cmd, a);
1696         if (cmd == CLI_INIT)
1697                 e->command = "restart when convenient";
1698         return res;
1699 }
1700
1701 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1702 {
1703         switch (cmd) {
1704         case CLI_INIT:
1705                 e->command = "core abort shutdown";
1706                 e->usage = 
1707                         "Usage: core abort shutdown\n"
1708                         "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1709                         "       call operations.\n";
1710                 return NULL;
1711         case CLI_GENERATE:
1712                 return NULL;
1713         }
1714
1715         if (a->argc != e->args)
1716                 return CLI_SHOWUSAGE;
1717         ast_cancel_shutdown();
1718         shuttingdown = 0;
1719         return CLI_SUCCESS;
1720 }
1721
1722 static char *handle_abort_shutdown_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1723 {
1724         char *res = handle_abort_shutdown(e, cmd, a);
1725         if (cmd == CLI_INIT)
1726                 e->command = "abort shutdown";
1727         return res;
1728 }
1729
1730 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1731 {
1732         switch (cmd) {
1733         case CLI_INIT:
1734                 e->command = "!";
1735                 e->usage = 
1736                         "Usage: !<command>\n"
1737                         "       Executes a given shell command\n";
1738                 return NULL;
1739         case CLI_GENERATE:
1740                 return NULL;
1741         }
1742
1743         return CLI_SUCCESS;
1744 }
1745 static const char warranty_lines[] = {
1746         "\n"
1747         "                           NO WARRANTY\n"
1748         "\n"
1749         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
1750         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
1751         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
1752         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
1753         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
1754         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
1755         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
1756         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
1757         "REPAIR OR CORRECTION.\n"
1758         "\n"
1759         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
1760         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
1761         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
1762         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
1763         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
1764         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
1765         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
1766         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
1767         "POSSIBILITY OF SUCH DAMAGES.\n"
1768 };
1769
1770 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1771 {
1772         switch (cmd) {
1773         case CLI_INIT:
1774                 e->command = "core show warranty";
1775                 e->usage = 
1776                         "Usage: core show warranty\n"
1777                         "       Shows the warranty (if any) for this copy of Asterisk.\n";
1778                 return NULL;
1779         case CLI_GENERATE:
1780                 return NULL;
1781         }
1782
1783         ast_cli(a->fd, warranty_lines);
1784
1785         return CLI_SUCCESS;
1786 }
1787
1788 static const char license_lines[] = {
1789         "\n"
1790         "This program is free software; you can redistribute it and/or modify\n"
1791         "it under the terms of the GNU General Public License version 2 as\n"
1792         "published by the Free Software Foundation.\n"
1793         "\n"
1794         "This program also contains components licensed under other licenses.\n"
1795         "They include:\n"
1796         "\n"
1797         "This program is distributed in the hope that it will be useful,\n"
1798         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1799         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1800         "GNU General Public License for more details.\n"
1801         "\n"
1802         "You should have received a copy of the GNU General Public License\n"
1803         "along with this program; if not, write to the Free Software\n"
1804         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
1805 };
1806
1807 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1808 {
1809         switch (cmd) {
1810         case CLI_INIT:
1811                 e->command = "core show license";
1812                 e->usage = 
1813                         "Usage: core show license\n"
1814                         "       Shows the license(s) for this copy of Asterisk.\n";
1815                 return NULL;
1816         case CLI_GENERATE:
1817                 return NULL;
1818         }
1819
1820         ast_cli(a->fd, license_lines);
1821
1822         return CLI_SUCCESS;
1823 }
1824
1825 #define ASTERISK_PROMPT "*CLI> "
1826
1827 #define ASTERISK_PROMPT2 "%s*CLI> "
1828
1829 /* deprecated cli entries */
1830 static struct ast_cli_entry cli_abort_shutdown_deprecated = AST_CLI_DEFINE(handle_abort_shutdown_deprecated, "Cancel a running shutdown.");
1831 static struct ast_cli_entry cli_stop_now_deprecated = AST_CLI_DEFINE(handle_stop_now_deprecated, "Shut down Asterisk immediately.");
1832 static struct ast_cli_entry cli_stop_gracefully_deprecated = AST_CLI_DEFINE(handle_stop_gracefully_deprecated, "Gracefully shut down Asterisk.");
1833 static struct ast_cli_entry cli_stop_when_convenient_deprecated = AST_CLI_DEFINE(handle_stop_when_convenient_deprecated, "Shut down Asterisk at empty call volume.");
1834 static struct ast_cli_entry cli_restart_now_deprecated = AST_CLI_DEFINE(handle_restart_now_deprecated, "Restart Asterisk immediately.");
1835 static struct ast_cli_entry cli_restart_gracefully_deprecated = AST_CLI_DEFINE(handle_restart_gracefully_deprecated, "Restart Asterisk gracefully.");
1836 static struct ast_cli_entry cli_restart_when_convenient_deprecated = AST_CLI_DEFINE(handle_restart_when_convenient_deprecated, "Restart Asterisk at empty call volume.");
1837 /* end deprecated cli entries */
1838
1839 static struct ast_cli_entry cli_asterisk[] = {
1840         AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown", .deprecate_cmd = &cli_abort_shutdown_deprecated),
1841         AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately", .deprecate_cmd = &cli_stop_now_deprecated),
1842         AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk", .deprecate_cmd = &cli_stop_gracefully_deprecated),
1843         AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume", .deprecate_cmd = &cli_stop_when_convenient_deprecated),
1844         AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately", .deprecate_cmd = &cli_restart_now_deprecated), 
1845         AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully", .deprecate_cmd = &cli_restart_gracefully_deprecated),
1846         AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume", .deprecate_cmd = &cli_restart_when_convenient_deprecated),
1847         AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
1848         AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
1849         AST_CLI_DEFINE(handle_version, "Display version info"),
1850         AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
1851 #if !defined(LOW_MEMORY)
1852         AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
1853         AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
1854 #if defined(HAVE_SYSINFO)
1855         AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
1856 #endif
1857         AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
1858         AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
1859         AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
1860 #endif /* ! LOW_MEMORY */
1861 };
1862
1863 static int ast_el_read_char(EditLine *el, char *cp)
1864 {
1865         int num_read = 0;
1866         int lastpos = 0;
1867         struct pollfd fds[2];
1868         int res;
1869         int max;
1870 #define EL_BUF_SIZE 512
1871         char buf[EL_BUF_SIZE];
1872
1873         for (;;) {
1874                 max = 1;
1875                 fds[0].fd = ast_consock;
1876                 fds[0].events = POLLIN;
1877                 if (!ast_opt_exec) {
1878                         fds[1].fd = STDIN_FILENO;
1879                         fds[1].events = POLLIN;
1880                         max++;
1881                 }
1882                 res = poll(fds, max, -1);
1883                 if (res < 0) {
1884                         if (errno == EINTR)
1885                                 continue;
1886                         ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1887                         break;
1888                 }
1889
1890                 if (!ast_opt_exec && fds[1].revents) {
1891                         num_read = read(STDIN_FILENO, cp, 1);
1892                         if (num_read < 1) {
1893                                 break;
1894                         } else 
1895                                 return (num_read);
1896                 }
1897                 if (fds[0].revents) {
1898                         res = read(ast_consock, buf, sizeof(buf) - 1);
1899                         /* if the remote side disappears exit */
1900                         if (res < 1) {
1901                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1902                                 if (!ast_opt_reconnect) {
1903                                         quit_handler(0, 0, 0, 0);
1904                                 } else {
1905                                         int tries;
1906                                         int reconnects_per_second = 20;
1907                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1908                                         for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
1909                                                 if (ast_tryconnect()) {
1910                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1911                                                         printf("%s", term_quit());
1912                                                         WELCOME_MESSAGE;
1913                                                         if (!ast_opt_mute)
1914                                                                 fdprint(ast_consock, "logger mute silent");
1915                                                         else 
1916                                                                 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
1917                                                         break;
1918                                                 } else
1919                                                         usleep(1000000 / reconnects_per_second);
1920                                         }
1921                                         if (tries >= 30 * reconnects_per_second) {
1922                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
1923                                                 quit_handler(0, 0, 0, 0);
1924                                         }
1925                                 }
1926                         }
1927
1928                         buf[res] = '\0';
1929
1930                         if (!ast_opt_exec && !lastpos)
1931                                 write(STDOUT_FILENO, "\r", 1);
1932                         write(STDOUT_FILENO, buf, res);
1933                         if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
1934                                 *cp = CC_REFRESH;
1935                                 return(1);
1936                         } else
1937                                 lastpos = 1;
1938                 }
1939         }
1940
1941         *cp = '\0';
1942         return (0);
1943 }
1944
1945 static char *cli_prompt(EditLine *el)
1946 {
1947         static char prompt[200];
1948         char *pfmt;
1949         int color_used = 0;
1950         char term_code[20];
1951
1952         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1953                 char *t = pfmt, *p = prompt;
1954                 memset(prompt, 0, sizeof(prompt));
1955                 while (*t != '\0' && *p < sizeof(prompt)) {
1956                         if (*t == '%') {
1957                                 char hostname[MAXHOSTNAMELEN]="";
1958                                 int i;
1959                                 struct timeval ts = ast_tvnow();
1960                                 struct ast_tm tm = { 0, };
1961 #ifdef linux
1962                                 FILE *LOADAVG;
1963 #endif
1964                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1965
1966                                 t++;
1967                                 switch (*t) {
1968                                 case 'C': /* color */
1969                                         t++;
1970                                         if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1971                                                 strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1972                                                 t += i - 1;
1973                                         } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1974                                                 strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1975                                                 t += i - 1;
1976                                         }
1977
1978                                         /* If the color has been reset correctly, then there's no need to reset it later */
1979                                         color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
1980                                         break;
1981                                 case 'd': /* date */
1982                                         if (ast_localtime(&ts, &tm, NULL))
1983                                                 ast_strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1984                                         break;
1985                                 case 'h': /* hostname */
1986                                         if (!gethostname(hostname, sizeof(hostname) - 1))
1987                                                 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1988                                         else
1989                                                 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1990                                         break;
1991                                 case 'H': /* short hostname */
1992                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
1993                                                 for (i = 0; i < sizeof(hostname); i++) {
1994                                                         if (hostname[i] == '.') {
1995                                                                 hostname[i] = '\0';
1996                                                                 break;
1997                                                         }
1998                                                 }
1999                                                 strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
2000                                         } else
2001                                                 strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
2002                                         break;
2003 #ifdef linux
2004                                 case 'l': /* load avg */
2005                                         t++;
2006                                         if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
2007                                                 float avg1, avg2, avg3;
2008                                                 int actproc, totproc, npid, which;
2009                                                 fscanf(LOADAVG, "%f %f %f %d/%d %d",
2010                                                         &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
2011                                                 if (sscanf(t, "%d", &which) == 1) {
2012                                                         switch (which) {
2013                                                         case 1:
2014                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
2015                                                                 break;
2016                                                         case 2:
2017                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
2018                                                                 break;
2019                                                         case 3:
2020                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
2021                                                                 break;
2022                                                         case 4:
2023                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
2024                                                                 break;
2025                                                         case 5:
2026                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
2027                                                                 break;
2028                                                         }
2029                                                 }
2030                                         }
2031                                         break;
2032 #endif
2033                                 case 's': /* Asterisk system name (from asterisk.conf) */
2034                                         strncat(p, ast_config_AST_SYSTEM_NAME, sizeof(prompt) - strlen(prompt) - 1);
2035                                         break;
2036                                 case 't': /* time */
2037                                         if (ast_localtime(&ts, &tm, NULL))
2038                                                 ast_strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
2039                                         break;
2040                                 case '#': /* process console or remote? */
2041                                         if (!ast_opt_remote) 
2042                                                 strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
2043                                         else
2044                                                 strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
2045                                         break;
2046                                 case '%': /* literal % */
2047                                         strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
2048                                         break;
2049                                 case '\0': /* % is last character - prevent bug */
2050                                         t--;
2051                                         break;
2052                                 }
2053                                 while (*p != '\0')
2054                                         p++;
2055                                 t++;
2056                         } else {
2057                                 *p = *t;
2058                                 p++;
2059                                 t++;
2060                         }
2061                 }
2062                 if (color_used) {
2063                         /* Force colors back to normal at end */
2064                         term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
2065                         if (strlen(term_code) > sizeof(prompt) - strlen(prompt) - 1) {
2066                                 ast_copy_string(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code) + 1);
2067                         } else {
2068                                 /* This looks wrong, but we've already checked the length of term_code to ensure it's safe */
2069                                 strncat(p, term_code, sizeof(term_code));
2070                         }
2071                 }
2072         } else if (remotehostname)
2073                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
2074         else
2075                 ast_copy_string(prompt, ASTERISK_PROMPT, sizeof(prompt));
2076
2077         return(prompt); 
2078 }
2079
2080 static char **ast_el_strtoarr(char *buf)
2081 {
2082         char **match_list = NULL, **match_list_tmp, *retstr;
2083         size_t match_list_len;
2084         int matches = 0;
2085
2086         match_list_len = 1;
2087         while ( (retstr = strsep(&buf, " ")) != NULL) {
2088
2089                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2090                         break;
2091                 if (matches + 1 >= match_list_len) {
2092                         match_list_len <<= 1;
2093                         if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2094                                 match_list = match_list_tmp;
2095                         } else {
2096                                 if (match_list)
2097                                         ast_free(match_list);
2098                                 return (char **) NULL;
2099                         }
2100                 }
2101
2102                 match_list[matches++] = ast_strdup(retstr);
2103         }
2104
2105         if (!match_list)
2106                 return (char **) NULL;
2107
2108         if (matches >= match_list_len) {
2109                 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2110                         match_list = match_list_tmp;
2111                 } else {
2112                         if (match_list)
2113                                 ast_free(match_list);
2114                         return (char **) NULL;
2115                 }
2116         }
2117
2118         match_list[matches] = (char *) NULL;
2119
2120         return match_list;
2121 }
2122
2123 static int ast_el_sort_compare(const void *i1, const void *i2)
2124 {
2125         char *s1, *s2;
2126
2127         s1 = ((char **)i1)[0];
2128         s2 = ((char **)i2)[0];
2129
2130         return strcasecmp(s1, s2);
2131 }
2132
2133 static int ast_cli_display_match_list(char **matches, int len, int max)
2134 {
2135         int i, idx, limit, count;
2136         int screenwidth = 0;
2137         int numoutput = 0, numoutputline = 0;
2138
2139         screenwidth = ast_get_termcols(STDOUT_FILENO);
2140
2141         /* find out how many entries can be put on one line, with two spaces between strings */
2142         limit = screenwidth / (max + 2);
2143         if (limit == 0)
2144                 limit = 1;
2145
2146         /* how many lines of output */
2147         count = len / limit;
2148         if (count * limit < len)
2149                 count++;
2150
2151         idx = 1;
2152
2153         qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2154
2155         for (; count > 0; count--) {
2156                 numoutputline = 0;
2157                 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2158
2159                         /* Don't print dupes */
2160                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2161                                 i--;
2162                                 ast_free(matches[idx]);
2163                                 matches[idx] = NULL;
2164                                 continue;
2165                         }
2166
2167                         numoutput++;
2168                         numoutputline++;
2169                         fprintf(stdout, "%-*s  ", max, matches[idx]);
2170                         ast_free(matches[idx]);
2171                         matches[idx] = NULL;
2172                 }
2173                 if (numoutputline > 0)
2174                         fprintf(stdout, "\n");
2175         }
2176
2177         return numoutput;
2178 }
2179
2180
2181 static char *cli_complete(EditLine *el, int ch)
2182 {
2183         int len = 0;
2184         char *ptr;
2185         int nummatches = 0;
2186         char **matches;
2187         int retval = CC_ERROR;
2188         char buf[2048];
2189         int res;
2190
2191         LineInfo *lf = (LineInfo *)el_line(el);
2192
2193         *(char *)lf->cursor = '\0';
2194         ptr = (char *)lf->cursor;
2195         if (ptr) {
2196                 while (ptr > lf->buffer) {
2197                         if (isspace(*ptr)) {
2198                                 ptr++;
2199                                 break;
2200                         }
2201                         ptr--;
2202                 }
2203         }
2204
2205         len = lf->cursor - ptr;
2206
2207         if (ast_opt_remote) {
2208                 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
2209                 fdprint(ast_consock, buf);
2210                 res = read(ast_consock, buf, sizeof(buf));
2211                 buf[res] = '\0';
2212                 nummatches = atoi(buf);
2213
2214                 if (nummatches > 0) {
2215                         char *mbuf;
2216                         int mlen = 0, maxmbuf = 2048;
2217                         /* Start with a 2048 byte buffer */                     
2218                         if (!(mbuf = ast_malloc(maxmbuf)))
2219                                 return (char *)(CC_ERROR);
2220                         snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
2221                         fdprint(ast_consock, buf);
2222                         res = 0;
2223                         mbuf[0] = '\0';
2224                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2225                                 if (mlen + 1024 > maxmbuf) {
2226                                         /* Every step increment buffer 1024 bytes */
2227                                         maxmbuf += 1024;                                        
2228                                         if (!(mbuf = ast_realloc(mbuf, maxmbuf)))
2229                                                 return (char *)(CC_ERROR);
2230                                 }
2231                                 /* Only read 1024 bytes at a time */
2232                                 res = read(ast_consock, mbuf + mlen, 1024);
2233                                 if (res > 0)
2234                                         mlen += res;
2235                         }
2236                         mbuf[mlen] = '\0';
2237
2238                         matches = ast_el_strtoarr(mbuf);
2239                         ast_free(mbuf);
2240                 } else
2241                         matches = (char **) NULL;
2242         } else {
2243                 char **p, *oldbuf=NULL;
2244                 nummatches = 0;
2245                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2246                 for (p = matches; p && *p; p++) {
2247                         if (!oldbuf || strcmp(*p,oldbuf))
2248                                 nummatches++;
2249                         oldbuf = *p;
2250                 }
2251         }
2252
2253         if (matches) {
2254                 int i;
2255                 int matches_num, maxlen, match_len;
2256
2257                 if (matches[0][0] != '\0') {
2258                         el_deletestr(el, (int) len);
2259                         el_insertstr(el, matches[0]);
2260                         retval = CC_REFRESH;
2261                 }
2262
2263                 if (nummatches == 1) {
2264                         /* Found an exact match */
2265                         el_insertstr(el, " ");
2266                         retval = CC_REFRESH;
2267                 } else {
2268                         /* Must be more than one match */
2269                         for (i = 1, maxlen = 0; matches[i]; i++) {
2270                                 match_len = strlen(matches[i]);
2271                                 if (match_len > maxlen)
2272                                         maxlen = match_len;
2273                         }
2274                         matches_num = i - 1;
2275                         if (matches_num >1) {
2276                                 fprintf(stdout, "\n");
2277                                 ast_cli_display_match_list(matches, nummatches, maxlen);
2278                                 retval = CC_REDISPLAY;
2279                         } else { 
2280                                 el_insertstr(el," ");
2281                                 retval = CC_REFRESH;
2282                         }
2283                 }
2284                 for (i = 0; matches[i]; i++)
2285                         ast_free(matches[i]);
2286                 ast_free(matches);
2287         }
2288
2289         return (char *)(long)retval;
2290 }
2291
2292 static int ast_el_initialize(void)
2293 {
2294         HistEvent ev;
2295         char *editor = getenv("AST_EDITOR");
2296
2297         if (el != NULL)
2298                 el_end(el);
2299         if (el_hist != NULL)
2300                 history_end(el_hist);
2301
2302         el = el_init("asterisk", stdin, stdout, stderr);
2303         el_set(el, EL_PROMPT, cli_prompt);
2304
2305         el_set(el, EL_EDITMODE, 1);             
2306         el_set(el, EL_EDITOR, editor ? editor : "emacs");               
2307         el_hist = history_init();
2308         if (!el || !el_hist)
2309                 return -1;
2310
2311         /* setup history with 100 entries */
2312         history(el_hist, &ev, H_SETSIZE, 100);
2313
2314         el_set(el, EL_HIST, history, el_hist);
2315
2316         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2317         /* Bind <tab> to command completion */
2318         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2319         /* Bind ? to command completion */
2320         el_set(el, EL_BIND, "?", "ed-complete", NULL);
2321         /* Bind ^D to redisplay */
2322         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2323
2324         return 0;
2325 }
2326
2327 static int ast_el_add_history(char *buf)
2328 {
2329         HistEvent ev;
2330
2331         if (el_hist == NULL || el == NULL)
2332                 ast_el_initialize();
2333         if (strlen(buf) > 256)
2334                 return 0;
2335         return (history(el_hist, &ev, H_ENTER, buf));
2336 }
2337
2338 static int ast_el_write_history(char *filename)
2339 {
2340         HistEvent ev;
2341
2342         if (el_hist == NULL || el == NULL)
2343                 ast_el_initialize();
2344
2345         return (history(el_hist, &ev, H_SAVE, filename));
2346 }
2347
2348 static int ast_el_read_history(char *filename)
2349 {
2350         char buf[256];
2351         FILE *f;
2352         int ret = -1;
2353
2354         if (el_hist == NULL || el == NULL)
2355                 ast_el_initialize();
2356
2357         if ((f = fopen(filename, "r")) == NULL)
2358                 return ret;
2359
2360         while (!feof(f)) {
2361                 fgets(buf, sizeof(buf), f);
2362                 if (!strcmp(buf, "_HiStOrY_V2_\n"))
2363                         continue;
2364                 if (ast_all_zeros(buf))
2365                         continue;
2366                 if ((ret = ast_el_add_history(buf)) == -1)
2367                         break;
2368         }
2369         fclose(f);
2370
2371         return ret;
2372 }
2373
2374 static void ast_remotecontrol(char * data)
2375 {
2376         char buf[80];
2377         int res;
2378         char filename[80] = "";
2379         char *hostname;
2380         char *cpid;
2381         char *version;
2382         int pid;
2383         char tmp[80];
2384         char *stringp = NULL;
2385
2386         char *ebuf;
2387         int num = 0;
2388
2389         read(ast_consock, buf, sizeof(buf));
2390         if (data)
2391                 write(ast_consock, data, strlen(data) + 1);
2392         stringp = buf;
2393         hostname = strsep(&stringp, "/");
2394         cpid = strsep(&stringp, "/");
2395         version = strsep(&stringp, "\n");
2396         if (!version)
2397                 version = "<Version Unknown>";
2398         stringp = hostname;
2399         strsep(&stringp, ".");
2400         if (cpid)
2401                 pid = atoi(cpid);
2402         else
2403                 pid = -1;
2404         if (!data) {
2405                 snprintf(tmp, sizeof(tmp), "core set verbose atleast %d", option_verbose);
2406                 fdprint(ast_consock, tmp);
2407                 snprintf(tmp, sizeof(tmp), "core set debug atleast %d", option_debug);
2408                 fdprint(ast_consock, tmp);
2409                 if (!ast_opt_mute)
2410                         fdprint(ast_consock, "logger mute silent");
2411                 else 
2412                         printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2413         }
2414         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
2415         remotehostname = hostname;
2416         if (getenv("HOME")) 
2417                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2418         if (el_hist == NULL || el == NULL)
2419                 ast_el_initialize();
2420
2421         el_set(el, EL_GETCFN, ast_el_read_char);
2422
2423         if (!ast_strlen_zero(filename))
2424                 ast_el_read_history(filename);
2425
2426         if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
2427                 char tempchar;
2428                 struct pollfd fds;
2429                 fds.fd = ast_consock;
2430                 fds.events = POLLIN;
2431                 fds.revents = 0;
2432                 while (poll(&fds, 1, 100) > 0)
2433                         ast_el_read_char(el, &tempchar);
2434                 return;
2435         }
2436         for (;;) {
2437                 ebuf = (char *)el_gets(el, &num);
2438
2439                 if (!ebuf && write(1, "", 1) < 0)
2440                         break;
2441
2442                 if (!ast_strlen_zero(ebuf)) {
2443                         if (ebuf[strlen(ebuf)-1] == '\n')
2444                                 ebuf[strlen(ebuf)-1] = '\0';
2445                         if (!remoteconsolehandler(ebuf)) {
2446                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
2447                                 if (res < 1) {
2448                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
2449                                         break;
2450                                 }
2451                         }
2452                 }
2453         }
2454         printf("\nDisconnected from Asterisk server\n");
2455 }
2456
2457 static int show_version(void)
2458 {
2459         printf("Asterisk %s\n", ast_get_version());
2460         return 0;
2461 }
2462
2463 static int show_cli_help(void) {
2464         printf("Asterisk %s, Copyright (C) 1999 - 2008, Digium, Inc. and others.\n", ast_get_version());
2465         printf("Usage: asterisk [OPTIONS]\n");
2466         printf("Valid Options:\n");
2467         printf("   -V              Display version number and exit\n");
2468         printf("   -C <configfile> Use an alternate configuration file\n");
2469         printf("   -G <group>      Run as a group other than the caller\n");
2470         printf("   -U <user>       Run as a user other than the caller\n");
2471         printf("   -c              Provide console CLI\n");
2472         printf("   -d              Enable extra debugging\n");
2473 #if HAVE_WORKING_FORK
2474         printf("   -f              Do not fork\n");
2475         printf("   -F              Always fork\n");
2476 #endif
2477         printf("   -g              Dump core in case of a crash\n");
2478         printf("   -h              This help screen\n");
2479         printf("   -i              Initialize crypto keys at startup\n");
2480         printf("   -I              Enable internal timing if Zaptel timer is available\n");
2481         printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
2482         printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
2483         printf("   -m              Mute debugging and console output on the console\n");
2484         printf("   -n              Disable console colorization\n");
2485         printf("   -p              Run as pseudo-realtime thread\n");
2486         printf("   -q              Quiet mode (suppress output)\n");
2487         printf("   -r              Connect to Asterisk on this machine\n");
2488         printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
2489         printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
2490         printf("                   belong after they are done\n");
2491         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
2492         printf("                   of output to the CLI\n");
2493         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
2494         printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
2495         printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
2496         printf("\n");
2497         return 0;
2498 }
2499
2500 static void ast_readconfig(void) 
2501 {
2502         struct ast_config *cfg;
2503         struct ast_variable *v;
2504         char *config = DEFAULT_CONFIG_FILE;
2505         char hostname[MAXHOSTNAMELEN] = "";
2506         struct ast_flags config_flags = { 0 };
2507         struct {
2508                 unsigned int dbdir:1;
2509                 unsigned int keydir:1;
2510         } found = { 0, 0 };
2511
2512         if (ast_opt_override_config) {
2513                 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
2514                 if (!cfg)
2515                         ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
2516         } else 
2517                 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
2518
2519         /* init with buildtime config */
2520         ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
2521         ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
2522         ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
2523         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
2524         ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
2525         ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
2526         ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
2527         ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
2528         ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
2529         ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
2530         ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
2531         ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
2532         ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
2533
2534         /* no asterisk.conf? no problem, use buildtime config! */
2535         if (!cfg) {
2536                 return;
2537         }
2538
2539         for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
2540                 if (!strcasecmp(v->name, "astctlpermissions"))
2541                         ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
2542                 else if (!strcasecmp(v->name, "astctlowner"))
2543                         ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
2544                 else if (!strcasecmp(v->name, "astctlgroup"))
2545                         ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
2546                 else if (!strcasecmp(v->name, "astctl"))
2547                         ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
2548         }
2549
2550         for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
2551                 if (!strcasecmp(v->name, "astetcdir")) {
2552                         ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
2553                 } else if (!strcasecmp(v->name, "astspooldir")) {
2554                         ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
2555                         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
2556                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
2557                         ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
2558                         if (!found.dbdir)
2559                                 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2560                 } else if (!strcasecmp(v->name, "astdbdir")) {
2561                         snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
2562                         found.dbdir = 1;
2563                 } else if (!strcasecmp(v->name, "astdatadir")) {
2564                         ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
2565                         if (!found.keydir)
2566                                 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2567                 } else if (!strcasecmp(v->name, "astkeydir")) {
2568                         snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
2569                         found.keydir = 1;
2570                 } else if (!strcasecmp(v->name, "astlogdir")) {
2571                         ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
2572                 } else if (!strcasecmp(v->name, "astagidir")) {
2573                         ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
2574                 } else if (!strcasecmp(v->name, "astrundir")) {
2575                         snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
2576                         snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
2577                         ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
2578                 } else if (!strcasecmp(v->name, "astmoddir")) {
2579                         ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
2580                 }
2581         }
2582
2583         for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
2584                 /* verbose level (-v at startup) */
2585                 if (!strcasecmp(v->name, "verbose")) {
2586                         option_verbose = atoi(v->value);
2587                 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
2588                 } else if (!strcasecmp(v->name, "timestamp")) {
2589                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
2590                 /* whether or not to support #exec in config files */
2591                 } else if (!strcasecmp(v->name, "execincludes")) {
2592                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
2593                 /* debug level (-d at startup) */
2594                 } else if (!strcasecmp(v->name, "debug")) {
2595                         option_debug = 0;
2596                         if (sscanf(v->value, "%d", &option_debug) != 1) {
2597                                 option_debug = ast_true(v->value);
2598                         }
2599 #if HAVE_WORKING_FORK
2600                 /* Disable forking (-f at startup) */
2601                 } else if (!strcasecmp(v->name, "nofork")) {
2602                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
2603                 /* Always fork, even if verbose or debug are enabled (-F at startup) */
2604                 } else if (!strcasecmp(v->name, "alwaysfork")) {
2605                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
2606 #endif
2607                 /* Run quietly (-q at startup ) */
2608                 } else if (!strcasecmp(v->name, "quiet")) {
2609                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
2610                 /* Run as console (-c at startup, implies nofork) */
2611                 } else if (!strcasecmp(v->name, "console")) {
2612                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
2613                 /* Run with high priority if the O/S permits (-p at startup) */
2614                 } else if (!strcasecmp(v->name, "highpriority")) {
2615                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
2616                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
2617                 } else if (!strcasecmp(v->name, "initcrypto")) {
2618                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
2619                 /* Disable ANSI colors for console (-c at startup) */
2620                 } else if (!strcasecmp(v->name, "nocolor")) {
2621                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
2622                 /* Disable some usage warnings for picky people :p */
2623                 } else if (!strcasecmp(v->name, "dontwarn")) {
2624                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
2625                 /* Dump core in case of crash (-g) */
2626                 } else if (!strcasecmp(v->name, "dumpcore")) {
2627                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
2628                 /* Cache recorded sound files to another directory during recording */
2629                 } else if (!strcasecmp(v->name, "cache_record_files")) {
2630                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
2631                 /* Specify cache directory */
2632                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
2633                         ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
2634                 /* Build transcode paths via SLINEAR, instead of directly */
2635                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
2636                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
2637                 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
2638                 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
2639                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
2640                 /* Enable internal timing */
2641                 } else if (!strcasecmp(v->name, "internal_timing")) {
2642                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
2643                 } else if (!strcasecmp(v->name, "maxcalls")) {
2644                         if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
2645                                 option_maxcalls = 0;
2646                         }
2647                 } else if (!strcasecmp(v->name, "maxload")) {
2648                         double test[1];
2649
2650                         if (getloadavg(test, 1) == -1) {
2651                                 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
2652                                 option_maxload = 0.0;
2653                         } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
2654                                 option_maxload = 0.0;
2655                         }
2656                 /* Set the maximum amount of open files */
2657                 } else if (!strcasecmp(v->name, "maxfiles")) {
2658                         option_maxfiles = atoi(v->value);
2659                         set_ulimit(option_maxfiles);
2660                 /* What user to run as */
2661                 } else if (!strcasecmp(v->name, "runuser")) {
2662                         ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
2663                 /* What group to run as */
2664                 } else if (!strcasecmp(v->name, "rungroup")) {
2665                         ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
2666                 } else if (!strcasecmp(v->name, "systemname")) {
2667                         ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
2668                 } else if (!strcasecmp(v->name, "autosystemname")) {
2669                         if (ast_true(v->value)) {
2670                                 if (!gethostname(hostname, sizeof(hostname) - 1))
2671                                         ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
2672                                 else {
2673                                         if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
2674                                                 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
2675                                         }
2676                                         ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
2677                                 }
2678                         }
2679                 } else if (!strcasecmp(v->name, "languageprefix")) {
2680                         ast_language_is_prefix = ast_true(v->value);
2681                 } else if (!strcasecmp(v->name, "lockmode")) {
2682                         if (!strcasecmp(v->value, "lockfile")) {
2683                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2684                         } else if (!strcasecmp(v->value, "flock")) {
2685                                 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
2686                         } else {
2687                                 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
2688                                         "defaulting to 'lockfile'\n", v->value);
2689                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
2690                         }
2691 #if defined(HAVE_SYSINFO)
2692                 } else if (!strcasecmp(v->name, "minmemfree")) {
2693                         /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
2694                          * if the amount of free memory falls below this watermark */
2695                         if ((sscanf(v->value, "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2696                                 option_minmemfree = 0;
2697                         }
2698 #endif
2699                 }
2700         }
2701         ast_config_destroy(cfg);
2702 }
2703
2704 static void *monitor_sig_flags(void *unused)
2705 {
2706         for (;;) {
2707                 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
2708                 int a;
2709                 poll(&p, 1, -1);
2710                 if (sig_flags.need_reload) {
2711                         sig_flags.need_reload = 0;
2712                         ast_module_reload(NULL);
2713                 }
2714                 if (sig_flags.need_quit) {
2715                         sig_flags.need_quit = 0;
2716                         quit_handler(0, 0, 1, 0);
2717                 }
2718                 read(sig_alert_pipe[0], &a, sizeof(a));
2719         }
2720
2721         return NULL;
2722 }
2723
2724 static void *canary_thread(void *unused)
2725 {
2726         struct stat canary_stat;
2727         struct timeval tv;
2728
2729         /* Give the canary time to sing */
2730         sleep(120);
2731
2732         for (;;) {
2733                 stat(canary_filename, &canary_stat);
2734                 tv = ast_tvnow();
2735                 if (tv.tv_sec > canary_stat.st_mtime + 60) {
2736                         ast_log(LOG_WARNING, "The canary is no more.  He has ceased to be!  He's expired and gone to meet his maker!  He's a stiff!  Bereft of life, he rests in peace.  His metabolic processes are now history!  He's off the twig!  He's kicked the bucket.  He's shuffled off his mortal coil, run down the curtain, and joined the bleeding choir invisible!!  THIS is an EX-CANARY.  (Reducing priority)\n");
2737                         ast_set_priority(0);
2738                         pthread_exit(NULL);
2739                 }
2740
2741                 /* Check the canary once a minute */
2742                 sleep(60);
2743         }
2744 }
2745
2746 /* Used by libc's atexit(3) function */
2747 static void canary_exit(void)
2748 {
2749         if (canary_pid > 0)
2750                 kill(canary_pid, SIGKILL);
2751 }
2752
2753 static void run_startup_commands(void)
2754 {
2755         int fd;
2756         struct ast_config *cfg;
2757         struct ast_flags cfg_flags = { 0 };
2758         struct ast_variable *v;
2759
2760         if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
2761                 return;
2762
2763         fd = open("/dev/null", O_RDWR);
2764         if (fd < 0)
2765                 return;
2766
2767         for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
2768                 if (ast_true(v->value))
2769                         ast_cli_command(fd, v->name);
2770         }
2771
2772         close(fd);
2773         ast_config_destroy(cfg);
2774 }
2775
2776 int main(int argc, char *argv[])
2777 {
2778         int c;
2779         char filename[80] = "";
2780         char hostname[MAXHOSTNAMELEN] = "";
2781         char tmp[80];
2782         char * xarg = NULL;
2783         int x;
2784         FILE *f;
2785         sigset_t sigs;
2786         int num;
2787         int isroot = 1;
2788         char *buf;
2789         const char *runuser = NULL, *rungroup = NULL;
2790         char *remotesock = NULL;
2791
2792         /* Remember original args for restart */
2793         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2794                 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2795                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2796         }
2797         for (x = 0; x < argc; x++)
2798                 _argv[x] = argv[x];
2799         _argv[x] = NULL;
2800
2801         if (geteuid() != 0)
2802                 isroot = 0;
2803
2804         /* if the progname is rasterisk consider it a remote console */
2805         if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2806                 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2807         }
2808         if (gethostname(hostname, sizeof(hostname)-1))
2809                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2810         ast_mainpid = getpid();
2811         ast_ulaw_init();
2812         ast_alaw_init();
2813         callerid_init();
2814         ast_builtins_init();
2815         ast_utils_init();
2816         tdd_init();
2817
2818         if (getenv("HOME")) 
2819                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2820         /* Check for options */
2821         while ((c = getopt(argc, argv, "mtThfFdvVqprRgciInx:U:G:C:L:M:e:s:")) != -1) {
2822                 switch (c) {
2823 #if defined(HAVE_SYSINFO)
2824                 case 'e':
2825                         if ((sscanf(&optarg[1], "%ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
2826                                 option_minmemfree = 0;
2827                         }
2828                         break;
2829 #endif
2830 #if HAVE_WORKING_FORK
2831                 case 'F':
2832                         ast_set_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2833                         break;
2834                 case 'f':
2835                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2836                         break;
2837 #endif
2838                 case 'd':
2839                         option_debug++;
2840                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2841                         break;
2842                 case 'c':
2843                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2844                         break;
2845                 case 'n':
2846                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2847                         break;
2848                 case 'r':
2849                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2850                         break;
2851                 case 'R':
2852                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2853                         break;
2854                 case 'p':
2855                         ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2856                         break;
2857                 case 'v':
2858                         option_verbose++;
2859                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2860                         break;
2861                 case 'm':
2862                         ast_set_flag(&ast_options, AST_OPT_FLAG_MUTE);
2863                         break;
2864                 case 'M':
2865                         if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2866                                 option_maxcalls = 0;
2867                         break;
2868                 case 'L':
2869                         if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2870                                 option_maxload = 0.0;
2871                         break;
2872                 case 'q':
2873                         ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2874                         break;
2875                 case 't':
2876                         ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2877                         break;
2878                 case 'T':
2879                         ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2880                         break;
2881                 case 'x':
2882                         ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2883                         xarg = ast_strdupa(optarg);
2884                         break;
2885                 case 'C':
2886                         ast_copy_string(cfg_paths.config_file, optarg, sizeof(cfg_paths.config_file));
2887                         ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2888                         break;
2889                 case 'I':
2890                         ast_set_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING);
2891                         break;
2892                 case 'i':
2893                         ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2894                         break;
2895                 case 'g':
2896                         ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2897                         break;
2898                 case 'h':
2899                         show_cli_help();
2900                         exit(0);
2901                 case 'V':
2902                         show_version();
2903                         exit(0);
2904                 case 'U':
2905                         runuser = ast_strdupa(optarg);
2906                         break;
2907                 case 'G':
2908                         rungroup = ast_strdupa(optarg);
2909                         break;
2910                 case 's':
2911                         remotesock = ast_strdupa(optarg);
2912                         break;
2913                 case '?':
2914                         exit(1);
2915                 }
2916         }
2917
2918         if (ast_opt_console || option_verbose || (ast_opt_remote && !ast_opt_exec)) {
2919                 ast_register_verbose(console_verboser);
2920                 WELCOME_MESSAGE;
2921         }
2922
2923         if (ast_opt_console && !option_verbose) 
2924                 ast_verbose("[ Booting...\n");
2925
2926         if (ast_opt_always_fork && (ast_opt_remote || ast_opt_console)) {
2927                 ast_log(LOG_WARNING, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
2928                 ast_clear_flag(&ast_options, AST_OPT_FLAG_ALWAYS_FORK);
2929         }
2930
2931         /* For remote connections, change the name of the remote connection.
2932          * We do this for the benefit of init scripts (which need to know if/when
2933          * the main asterisk process has died yet). */
2934         if (ast_opt_remote) {
2935                 strcpy(argv[0], "rasterisk");
2936                 for (x = 1; x < argc; x++) {
2937                         argv[x] = argv[0] + 10;
2938                 }
2939         }
2940
2941         if (ast_opt_console && !option_verbose) 
2942                 ast_verbose("[ Reading Master Configuration ]\n");
2943         ast_readconfig();
2944
2945         if (ast_opt_remote && remotesock != NULL)
2946                 ast_copy_string((char *) cfg_paths.socket_path, remotesock, sizeof(cfg_paths.socket_path));
2947
2948         if (!ast_language_is_prefix && !ast_opt_remote)
2949                 ast_log(LOG_WARNING, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n");
2950
2951         if (ast_opt_dump_core) {
2952                 struct rlimit l;
2953                 memset(&l, 0, sizeof(l));
2954                 l.rlim_cur = RLIM_INFINITY;
2955                 l.rlim_max = RLIM_INFINITY;
2956                 if (setrlimit(RLIMIT_CORE, &l)) {
2957                         ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2958                 }
2959         }
2960
2961         if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2962                 rungroup = ast_config_AST_RUN_GROUP;
2963         if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2964                 runuser = ast_config_AST_RUN_USER;
2965
2966         /* Must install this signal handler up here to ensure that if the canary
2967          * fails to execute that it doesn't kill the Asterisk process.
2968          */
2969         signal(SIGCHLD, child_handler);
2970
2971 #ifndef __CYGWIN__
2972
2973         if (isroot) {
2974                 ast_set_priority(ast_opt_high_priority);
2975                 if (ast_opt_high_priority) {
2976                         snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
2977
2978                         canary_pid = fork();
2979                         if (canary_pid == 0) {
2980                                 char canary_binary[128], *lastslash;
2981                                 int fd;
2982
2983                                 /* Reset signal handler */
2984                                 signal(SIGCHLD, SIG_DFL);
2985
2986                                 for (fd = 0; fd < 100; fd++)
2987                                         close(fd);
2988
2989                                 execlp("astcanary", "astcanary", canary_filename, (char *)NULL);
2990
2991                                 /* If not found, try the same path as used to execute asterisk */
2992                                 ast_copy_string(canary_binary, argv[0], sizeof(canary_binary));
2993                                 if ((lastslash = strrchr(canary_binary, '/'))) {
2994                                         ast_copy_string(lastslash + 1, "astcanary", sizeof(canary_binary) + canary_binary - (lastslash + 1));
2995                                         execl(canary_binary, "astcanary", canary_filename, (char *)NULL);
2996                                 }
2997
2998                                 /* Should never happen */
2999                                 _exit(1);
3000                         } else if (canary_pid > 0) {
3001                                 pthread_t dont_care;
3002                                 ast_pthread_create_detached(&dont_care, NULL, canary_thread, NULL);
3003                         }
3004
3005                         /* Kill the canary when we exit */
3006                         atexit(canary_exit);
3007                 }
3008         }
3009
3010         if (isroot && rungroup) {
3011                 struct group *gr;
3012                 gr = getgrnam(rungroup);
3013                 if (!gr) {
3014                         ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
3015                         exit(1);
3016                 }
3017                 if (setgid(gr->gr_gid)) {
3018                         ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
3019                         exit(1);
3020                 }
3021                 if (setgroups(0, NULL)) {
3022                         ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
3023                         exit(1);
3024                 }
3025                 if (option_verbose)
3026                         ast_verbose("Running as group '%s'\n", rungroup);
3027         }
3028
3029         if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
3030 #ifdef HAVE_CAP
3031                 int has_cap = 1;
3032 #endif /* HAVE_CAP */
3033                 struct passwd *pw;
3034                 pw = getpwnam(runuser);
3035                 if (!pw) {
3036                         ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
3037                         exit(1);
3038                 }
3039 #ifdef HAVE_CAP
3040                 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
3041                         ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
3042                         has_cap = 0;
3043                 }
3044 #endif /* HAVE_CAP */
3045                 if (!isroot && pw->pw_uid != geteuid()) {
3046                         ast_log(LOG_ERROR, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
3047                         exit(1);
3048                 }
3049                 if (!rungroup) {
3050                         if (setgid(pw->pw_gid)) {
3051                                 ast_log(LOG_WARNING, "Unable to setgid to %d!\n", (int)pw->pw_gid);
3052                                 exit(1);
3053                         }
3054                         if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
3055                                 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
3056                                 exit(1);
3057                         }
3058                 }
3059                 if (setuid(pw->pw_uid)) {
3060                         ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
3061                         exit(1);
3062                 }
3063                 if (option_verbose)
3064                         ast_verbose("Running as user '%s'\n", runuser);
3065 #ifdef HAVE_CAP
3066                 if (has_cap) {
3067                         cap_t cap;
3068
3069                         cap = cap_from_text("cap_net_admin=ep");
3070
3071                         if (cap_set_proc(cap))
3072                                 ast_log(LOG_WARNING, "Unable to install capabilities.\n");
3073
3074                         if (cap_free(cap))
3075                                 ast_log(LOG_WARNING, "Unable to drop capabilities.\n");
3076                 }
3077 #endif /* HAVE_CAP */
3078         }
3079
3080 #endif /* __CYGWIN__ */
3081
3082 #ifdef linux
3083         if (geteuid() && ast_opt_dump_core) {
3084                 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
3085                         ast_log(LOG_WARNING, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
3086                 }       
3087         }
3088 #endif
3089
3090         ast_term_init();
3091         printf("%s", term_end());
3092         fflush(stdout);
3093
3094         if (ast_opt_console && !option_verbose) 
3095                 ast_verbose("[ Initializing Custom Configuration Options ]\n");
3096         /* custom config setup */
3097         register_config_cli();
3098         read_config_maps();
3099         
3100         if (ast_opt_console) {
3101                 if (el_hist == NULL || el == NULL)
3102                         ast_el_initialize();
3103
3104                 if (!ast_strlen_zero(filename))
3105                         ast_el_read_history(filename);
3106         }
3107
3108         if (ast_tryconnect()) {
3109             &nbs