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