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