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