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