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