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