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