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