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