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