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