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