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