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