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