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