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