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