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