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