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