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