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