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