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