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