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