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