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