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