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