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